Friday, June 15, 2012

MyTooltip jQuery Plugin

MyTooltip is a very lightweight jQuery tooltip plugin see? I made ​​this just to give something simple to you who just want to beautify the default tooltip appearance.

MyTooltip jQuery Plugin

MyTooltip adalah plugin jQuery yang luar biasa ringan. Saya membuat ini sekedar untuk memberikan alternatif yang jauh lebih sederhana sebagai pengganti plugin tooltip yang lain kepada Anda yang hanya ingin mempercantik tampilan tooltip standar:

Lihat Demo Unduh Plugin Unduh Plugin (Minified)

Dasar Penggunaan

Sertakan jQuery dan plugin tooltip di atas kode </head>. Untuk memodifikasi tampilan tooltip, cukup seleksi elemen yang Anda inginkan kemudian terapkan method .myTooltip() seperti ini:

<script src="js/jquery.js"></script>
<script src="js/mytooltip.js"></script>
<script>
$(document).ready(function() {
    $('a').myTooltip();
});
</script>

Pengaturan Lanjutan

Hanya ada sedikit opsi lanjutan yang bisa Anda atur di sini (seperti yang Saya katakan di atas: luar biasa ringan) yaitu meliputi atribut, posisi dan efek:

$('a').myTooltip("title", {
    top: 20,
    left: 20,
    fade: false,
    time: 400
});
Opsi Keterangan
"title" Artinya bahwa tooltip akan menampilkan teks yang berasal dari atribut title pada elemen target. Sebagai contoh, jika Anda mengubah "title" menjadi "href", maka tooltip yang tampil berupa URL.
top Digunakan untuk mengatur jarak atas tooltip dari pointer.
left Digunakan untuk mengatur jarak samping kiri tooltip dari pointer.
fade Jika bernilai true maka tooltip akan ditampilkan dengan efek animasi .fadeIn()
time Digunakan untuk mengatur kecepatan efek .fadeIn()

Contoh Penerapan: Atribut Pengganti

Katakanlah kita tidak ingin menampilkan teks tooltip dari atribut title, maka kita bisa mengubah target atributnya seperti ini:

<img src="img/my-image.jpg" alt="This is a tooltip!">
$('img').myTooltip("alt"); // Tooltip akan menampilkan nilai atribut `alt` dari gambar

Contoh Penerapan: Modifikasi Posisi

Posisi tooltip terhadap pointer bisa dimodifikasi:

// Tooltip akan memiliki jarak atas
// sebesar 50 piksel dan jarak samping
// sebesar 70 piksel

$('a').myTooltip("title", {
    top: 50,
    left: 70
});

Contoh Penerapan: Mengaktifkan Efek Fade Saat Tooltip Ditampilkan

Set opsi fade menjadi true dan tentukan kecepatan animasi pada opsi time jika perlu:

$('a').myTooltip("title", {
    fade: true,
    time: 1000
});

Contoh Penerapan: Modifikasi Tampilan Spesifik pada Setiap Tooltip

Untuk menciptakan tampilan spesifik tentunya kita membutuhkan kelas yang spesifik juga. Di sini Saya memberikan fasilitas untuk menyisipkan kelas spesifik pada tooltip yang diinginkan dengan cara menambahkan atribut data-custom pada elemen target dengan nilai yang nantinya akan menjadi kelas baru pada tooltip:

<a href="#" data-custom="yourClass" title="This is a custom tooltip!">Example Link</a>

Kemudian atur tampilannya sesuka hati dengan cara menambahkan kode CSS khusus untuk kelas yang sudah Anda tentukan dalam atribut data-custom:

.yourClass {
  background-color:red;
  color:yellow;
  /* Dan sebagainya... */
}

Integrasi Plugin ke Blogger

Masuk ke halaman editor HTML Template Anda:

Mengedit HTML Template
Mengedit HTML

Temukan kode ini:

]]></b:skin>

Salin kode CSS di bawah ini dan letakkan di atasnya:

.tooltip {
  background-color:black;
  color:white;
  padding:5px 10px;
  display:block;
  -webkit-box-shadow:0 1px 2px rgba(0,0,0,.4);
  -moz-box-shadow:0 1px 2px rgba(0,0,0,.4);
  box-shadow:0 1px 2px rgba(0,0,0,.4);
}

Setelah itu temukan kode ini:

</head>

Salin kode ini dan letakkan di atasnya:

<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'></script><script src='http://dte-project.googlecode.com/svn/trunk/myTooltip/mytooltip.min.js'></script>
<script>
//<![CDATA[
$(document).ready(function() {
    $('a').myTooltip();
});
//]]>
</script>

Jika kode yang Saya beri garis bawah sudah ada di dalam templat, maka Anda tidak perlu menambahkannya lagi. Hapus skrip tersebut!

Klik Simpan Template.

Labels: , ,

Wednesday, June 13, 2012

Eksperimen Syntax Highlighter

Syntax Highlighter

HAAAAAHHHHHHHHH!!!! Mulai iseng lagi…

jQuery

// Pure jQuery Syntax Highlighter by Taufik Nurrohman
// Still an experimental :)
// https://plus.google.com/108949996304093815163/about

$(function() {
    $('pre').each(function() {
        var list = "(true|false|null|main|in|endif|if|endfor|for|while|finally|var|new|function|do|return|void|else|break|catch|instanceof|with|throw|case|default|try|this|switch|continue|typeof|delete)",
            rep1 = new RegExp(list + " ", "ig"),
            rep2 = new RegExp(list + "( ?)<span", "ig"),
            $this = $(this);
        $this.html($this.html()
        .replace(/(<br>|\n)$/ig, "")
        .replace(/(\t)/g, "    ")
        .replace(/&quot;/ig, "\"")
        .replace(/&#39;|&apos;/ig, "\'")
        .replace(/(.?)'(.*?)'/g, "$1<span class='str'>\'$2\'</span>")
        .replace(/(.?)"(.*?)"/g, "$1<span class='str'>\"$2\"</span>")
        .replace(/(.?)(""|'')/g, "$1<span class='value'>$2</span>")
        .replace(/(#[A-F0-9]{3,6})/ig, "<span class='hex'>$1</span>")
        .replace(/(\d+(?!(.*&lt;)))/g, "<span class='num'>$1</span>")
        .replace(/((#|\.)[\-_A-Z0-9]+)/ig, "<span class='selector'>$1</span>")
        .replace(/(\{|\}|\(|\)|\[|\])/g, "<span class='bracket'>$1</span>")
        .replace(/&lt;(.*?)&gt;/g, "<span class='tag'>&lt;$1&gt;</span>")
        .replace(/&lt;!--([\s\S]*?)--&gt;/gm, "<span class='comment'>&lt;!--$1--&gt;</span>")
        .replace(/\/\*([\s\S]*?)\*\//gm, "<span class='comment'>/*$1*/</span>")
        .replace(/[^\:]\/\/(.*)/g, "<span class='comment'>//$1</span>")
        .replace(/<\/span>\/(.*)\/([gim]+),( ?)<span class='str'>/g, "</span><span class='regexp'>/$1/$2</span>, <span class='str'>")
        .replace(rep1, "<span class='keyword'>$1</span> ")
        .replace(rep2, "<span class='keyword'>$1</span>$2<span")
        .replace(/function<\/span> (.[^<]*)<span/g, "function</span> <span class='name'>$1</span><span")
        .replace(/([\-_A-Z]+)(?=(\s+|)):(.(?!\{)*)/ig, "<span class='attribute'>$1</span>:$2$3")
        .replace(/h<span class='num'>([1-6])<\/span>/ig, "h$1")
        .replace(/!important/ig, "<mark class='important'>!important</mark>")
        .replace(/&lt;!(doctype)(.*)&gt;/ig, "<span class='doctype'>&lt;!$1$2&gt;</span>")
        .replace(/@<span class='attribute'>(import|page|media|charset|keyframes|font-face)<\/span>/ig, "@$1")
        .replace(/(@(import|page|media|charset|keyframes|font-face))/ig, "<span class='keyword'>$1</span>")
        .replace(/<span class='bracket'>\[<\/span>(.*)<span class='bracket'>\]<\/span>/ig, "<span class='array'>[$1]</span>")
        ).find('.str span, .regexp span, .comment span, .doctype span, .hex span, .array span, .url span').contents().unwrap();
        $this.append('<div class="the-num"></div>');

        // Insert the line number
        var num = $this.html().split(/\n|<br>/).length,
            count = 0;
        for (var i = 0; i < num; i++) {
            count = count + 1;
            $this.find('.the-num').append(count + '.<br/>');
        }
        $this.css('padding-left', $this.find('.the-num').outerWidth()+14);

    });
});

CSS

pre {
  background-color:white;
  color:#069;
  padding:0em 1em;
  overflow:auto;
  white-space:pre;
  word-wrap:normal;
  font:bold 12px/1.5em "Consolas","Bitstream Vera Sans Mono","Courier New",Courier,monospace !important;
  position:relative;
  margin:0 0 1em;
}

pre .the-num {
  position:absolute;
  top:0;
  bottom:0;
  left:0;
  padding:0 1em;
  color:#999;
  background-color:#eee;
  border-right:2px solid #ccc;
}

pre .bracket   {color:darkblue;}
pre .tag,
pre .tag .keyword,
pre .tag .attribute {color:blue;}
pre .selector  {color:blue;}
pre .attribute,
pre .regexp    {color:darkorange;}
pre .str       {color:green;}
pre .tag .str  {color:brown;}
pre .keyword   {color:darkred;}
pre .comment   {font-style:italic;color:#999;}
pre .num,
pre .hex       {color:darkviolet;}
pre .name,
pre .important,
pre .array     {color:red;}
pre .important {background-color:yellow;}
pre .doctype   {color:magenta;}

Lihat Demo


Lainnya

Labels: , , , ,

Monday, June 11, 2012

Draggable Tanpa jQuery UI

Draggable Without jQuery UI
$(function() {
    $('body').on('mousedown', 'div', function() {
        $(this).addClass('draggable').parents().on('mousemove', function(e) {
            $('.draggable').offset({
                top: e.pageY - $('.draggable').outerHeight() / 2,
                left: e.pageX - $('.draggable').outerWidth() / 2
            }).on('mouseup', function() {
                $(this).removeClass('draggable');
            });
        });
        e.preventDefault();
    }).on('mouseup', function() {
        $('.draggable').removeClass('draggable');
    });
});

Lihat Demo Kejutan =)

Pembaharuan 26 Februari 2013

Kode di atas kurang cerdas karena jQuery hanya memposisikan kursor di tengah elemen bergerak. Di sini Saya sudah membuat plugin sederhana yang lebih cerdas dan dapat menyesuaikan posisi pointer terhadap elemen, tidak harus selalu di tengah elemen:

Lihat Demo Telah Dihosting

Penggunaan

jQuery

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="//cdn.rawgit.com/tovic/dte-project/3c9ce0ac972ba889fc06e0374c866dd034198684/jquery-draggable/draggable.min.js"></script>
<script>
$(function() {
    $('.box').drags();
});
</script>

HTML

<div class="box">Saya bisa digeser...</div>

Labels: , ,

Basic jQuery Text/Image Rotator

Basic jQuery Text/Image Rotator

Barusan Saya menemukan kode bagus di sini: Creating a Text Rotator with jQuerySangat sederhana dan mudah dipahami. Sebuah fungsi jQuery slider dasar untuk merotasikan sekelompok elemen di dalam kontainer yang seringkali dicari. Saya mencoba mengonversikannya menjadi plugin seperti ini:

Plugin

(function($) {
    $.fn.rotator = function(settings) {
        settings = jQuery.extend({
            interval: 3000,
            speed: 1000
        }, settings);

        return this.each(function() {
            var $t = $(this),
                $item = $t.children().addClass('item').hide();

            $t.addClass('rotator');

            // Jalankan animasi jika jumlah item lebih dari satu!
            if ($item.length > 1) {
                // Tambahkan kelas 'current' pada item pertama sebagai penanda awal slide
                $item.first().addClass('current').fadeIn(settings.speed);
                // Menjalankan interval fungsi animasi dengan waktu interval yang telah ditentukan
                setInterval(function() {
                    var c = $t.find('.current');
                    // Jika item (slide) setelah item aktif tidak ditemukan...
                    if (c.next().length === 0) {
                        // Hilangkan kelas 'current' pada item aktif
                        c.removeClass('current').fadeOut(settings.speed);
                        // Kemudian tambahkan kelas 'current' ke item pertama...
                        // sehingga rotasi bisa dimulai kembali dari awal!
                        $item.first().addClass('current').fadeIn(settings.speed);
                    } else {
                        // Jika tidak (jika item setelah item aktif ditemukan) ...
                        // Hilangkan kelas 'current' pada item aktif
                        // Kemudian tambahkan kelas 'current' pada item berikutnya
                        c.removeClass('current').fadeOut(settings.speed).next().addClass('current').fadeIn(settings.speed);
                    }
                }, settings.interval);
            }
        });
    };
})(jQuery);

Kerangka HTML

<div id="slide">
    <div>Konten 1</div>
    <div>Konten 2</div>
    <div>Konten 3</div>
    <div>Konten 4</div>
</div>

Penggunaan

$(function() {
    $('#slide').rotator({
        interval: 3000,
        speed: 1000
    });
});
Opsi Keterangan
interval Digunakan untuk menentukan interval pergantian slide
speed Digunakan untuk menentukan kecepatan animasi pergantian slide

Demo: Sebagai Text Rotator Demo: Sebagai Image Rotator

Labels: , ,

Sunday, June 10, 2012

Simple Tab jQuery Plugin

Simple Tab is a jQuery plugin to transform a group of elements into a tab widget.

Simple Tab jQuery Plugin

Simple Tab adalah plugin jQuery untuk mengubah sekelompok elemen menjadi sebuah widget tabulasi:

Lihat Demo Unduh Plugin

Dasar Penggunaan

Berbeda dengan plugin tabulasi yang lainnya, plugin ini relatif lebih mudah dalam hal implementasi karena Anda tidak akan lagi direpotkan dengan pembuatan markup tabulasi yang rumit. Biarkan jQuery yang melakukan semuanya, sementara yang perlu Anda lakukan hanyalah menciptakan beberapa elemen <div> di dalam sebuah kontainer saja seperti ini:

<div id="tab">
  <div data-tab="Tab-1">Content 1</div>
  <div data-tab="Tab-2">Content 2</div>
  <div data-tab="Tab-3">Content 3</div>
  <div data-tab="Tab-4">Content 4</div>
</div>

Setiap nilai atribut data-tab nantinya akan berubah menjadi elemen tab di atas tubuh tab.

Selanjutnya adalah kode CSS dasar:

.simpleTab {
  width:400px;
  margin:50px auto;
  color:black;
  text-align:left;
}

.simpleTab .tab-wrapper {
  margin:0;
  padding:0;
  height:30px;
}

.simpleTab .tab-wrapper li {
  margin:0;
  padding:0;
  float:left;
  list-style:none;
  display:inline;
}

.simpleTab .tab-wrapper a {
  margin:0 2px 0 0;
  display:block;
  font:normal bold 12px/30px Arial,Sans-Serif;
  padding:0 15px;
  background-color:black;
  color:white;
  text-decoration:none;
  border:1px solid black;
  border-bottom:none;
  position:relative;
  z-index:1;
  outline:none;
}

.simpleTab .tab-content {
  clear:both;
  padding:10px;
  background-color:yellow;
  border:1px solid black;
  position:relative;
  z-index:2;
  top:-1px;
  height:170px;
}

.simpleTab .tab-wrapper a.activeTab {
  background-color:yellow;
  color:black;
  z-index:3;
}

Setelah kerangka tercipta, seleksi grup elemen yang Anda buat dan terapkan plugin SimpleTab seperti ini:

<script src="js/jquery-1.7.2.min.js"></script>
<script src="js/simple-tab.min.js"></script>
<script>
$(function() {
    $('#tab').simpleTab();
});
</script>

Pengaturan Lanjutan

Ada beberapa opsi tambahan di dalamnya yang bisa Anda atur sesuai dengan kebutuhan:

$('#tab').simpleTab({
    active: 1,
    fx: null,
    showSpeed: 400,
    hideSpeed: 400,
    showEasing: null,
    hideEasing: null
});
Opsi Keterangan
active Digunakan untuk menentukan tab ke berapa yang akan ditampilkan saat pertama kali
fx Digunakan untuk menentukan tipe efek animasi saat pergantian tab terjadi. Ada tiga macam efek lanjutan, yaitu "fade", "slide" dan "fancyslide". Jika tipe efek tidak ditentukan, pergantian tabulasi akan berjalan tanpa efek animasi
showSpeed Digunakan untuk menentukan kecepatan pembukaan konten tab
hideSpeed Digunakan untuk menentukan kecepatan penutupan konten tab
showEasing Digunakan untuk menentukan tipe easing saat pembukaan konten tab
hideEasing Digunakan untuk menentukan tipe easing saat penutupan konten tab.

Labels: , ,

Friday, June 8, 2012

Plugin jQuery Accordion Sederhana

Simple jQuery Accordion Plugin

Plugin

/**
 * Simple jQuery Accordion Plugin
 * Author: Taufik Nurrohman
 * Date: 8 June 2012
 * https://plus.google.com/108949996304093815163/about
 */

(function($) {
    $.fn.accordion = function(settings) {
        settings = jQuery.extend({
            active: 1,
            sUpSpeed: 400,
            sDownSpeed: 400,
            sUpEasing: null,
            sDownEasing: null
        }, settings);

        return this.each(function() {
            var $this = $(this),
                $item = $this.children('div[data-header]'),
                activePanel = settings.active - 1;

            $item.each(function() {
                $(this).hide().before('<h2 class="accordion-header">' + $(this).data('header') + '</h2>');
            });

            $this.children('div:eq(' + activePanel + ')').show().prev().addClass('active');
            $this.find('.accordion-header').on("click", function() {
                $this.children('h2').removeClass('active');
                $item.slideUp(settings.sUpSpeed, settings.sUpEasing);
                $(this).addClass('active').next().slideDown(settings.sDownSpeed, settings.sDownEasing);
            });

        });
    };

})(jQuery);

Dasar Penggunaan

Cara menggunakannya sama dengan plugin jQuery UI Accordion. Hanya saja Saya mencoba menyederhanakan kerangka dan opsinya untuk kebutuhan skala kecil.

Pertama-tama buat kerangka HTML seperti ini:

<div id="accordion">
    <div data-header="Accordion Title 1">Content 1</div>
    <div data-header="Accordion Title 2">Content 2</div>
    <div data-header="Accordion Title 3">Content 3</div>
    <div data-header="Accordion Title 4">Content 4</div>
</div>

Setiap nama header akordion disimpan di dalam atribut data-header. Plugin di atas nantinya akan memindahkan/menyalin nilai atribut tersebut untuk disisipkan ke dalam elemen <h2> yang akan diciptakan secara otomatis.

Berikutnya adalah kode CSS dasar untuk menciptakan dimensi akordion seperlunya. Silakan dimodifikasi sendiri:

#accordion {
  width:300px;
  background-color:green;
  border:2px solid black;
}

#accordion h2.accordion-header {
  cursor:pointer;
  background-color:black;
  font:bold 12px Arial,Sans-Serif;
  color:white;
  padding:10px 15px;
  margin:0px 0px;
}

#accordion h2.active {
  background-color:yellow;
  color:black;
}

#accordion div[data-header] {
  padding:10px;
}

Seleksi elemen induk pada kerangka yang Anda buat lalu terapkan plugin .accordion():

$(function() {
    $('#accordion').accordion();
});

Pengaturan Lanjutan

Ada lima buah opsi yang Saya buat untuk pengaturan tingkat lanjut:

$(function() {
    $('#accordion').accordion({
        active: 1,
        sUpSpeed: 400,
        sDownSpeed: 400,
        sUpEasing: null,
        sDownEasing: null
    });
});
Opsi Keterangan
active Digunakan untuk menentukan panel yang akan terbuka saat pertama kali. Nilai 1 memiliki arti bahwa panel pertama akan terbuka
sUpSpeed Digunakan untuk menentukan kecepatan penutupan panel
sUpSpeed Digunakan untuk menentukan kecepatan pembukaan panel
sUpEasing Digunakan untuk menentukan tipe easing panel saat panel menutup (misal: "easeOutBounce")
sDownEasing Digunakan untuk menentukan tipe easing panel saat panel membuka.

Lihat Demo

Labels: , , ,

Thursday, June 7, 2012

Berbicara Tentang Optimasi Kecepatan Muat Halaman

Beberapa orang berpendapat bahwa kompresi JavaScript, CSS, gambar atau bahkan HTML bisa mempercepat proses muat halaman sebuah situs. Tapi Saya tidak pernah setuju dengan itu 100%. Ada begitu banyak hal yang harus menjadi pertimbangan lebih lanjut dibandingkan sekedar memfokuskan perhatian Anda terhadap perhitungan besar kecilnya ukuran file. Kebanyakan alat kompresi hanya akan memperkecil ukuran berkas tidak lebih dari 20%:

Hasil Kompresi CSS
Hasil Kompresi CSS – CSSDrive

Dan lagipula, kompresi yang dilakukan hanya berada pada seputar peringkasan variabel dan pembuangan karakter spasi yang tidak diperlukan. Itu sama sekali tidak mempercepat proses muat halaman sepenuhnya, itu hanya akan mempercepat proses pengunduhan file secara sepihak. Dalam hal ini adalah CSS/JavaScript yang notabene hanyalah file berupa teks, sehingga mengunduh teks yang dikompresi dengan teks yang tidak dikompresi tidak akan memberikan begitu banyak perbedaan. Kecepatan muat halaman situs tidak semata-mata dipengaruhi oleh faktor ukuran file, tapi juga oleh validasi, permintaan HTTP dan juga ketepatan pendeklarasian kode tugas yang akan memberikan timbal balik berupa kemudahan peramban dalam membaca dokumen Anda.

JavaScript Packer vs. Minifier

Mana yang lebih cepat dimuat, antara JavaScript yang dikompres dengan teknik Packer dan teknik Minifier? Seharusnya Packer lebih cepat karena mereka akan mengompres kode jauh lebih banyak dibandingkan Minifier.

Mohon pertimbangkan sekali lagi. Packer memang akan memperkecil ukuran JavaScript jauh lebih banyak dibandingkan Minifier, tapi imbasnya adalah peramban harus memberikan waktu tambahan untuk menyusun kembali kode-kode yang sudah dipecah meskipun kenyataannya ukuran mereka sudah diperkecil. Packer (dan Obfuscator) akan membuat JavaScript lebih lama dimuat bukan karena ukuran file yang besar, namun karena membuat waktu membaca peramban menjadi lebih lama. Saat kita mengompres JavaScript dengan Packer atau Obfuscator, kita seperti sedang memberikan teka-teki sandi perintah terlebih dahulu untuk dijawab oleh peramban sebelum pada akhirnya mereka berhasil menjawabnya dan menjalankan tugasnya. Lebih baik gunakan Minifier dibandingkan Packer jika memang ingin mengurangi ukuran file JavaScript:

Menggunakan Base62 menambahkan langkah tambahan sebelum JavaScript dapat dimanfaatkan oleh klien. Untuk jenis perpustakaan jQuery langkah ini dapat mengambil ekstra waktu 100 - 500ms pada klien, tergantung pada banyak faktor. Sekarang kita dapat membandingkan pengurangan "waktu untuk mengunduh script" dan "waktu tambahan yang dibutuhkan untuk mengeksekusi script". Ini (packer/teknik base62) dapat mengurangi waktu pengunduhan sebanyak 50ms tetapi mengambil ekstra 100ms hanya untuk memprosesnya (menyusun kembali kode yang sudah terpecah-pecah) - Sumber

Lalu bagaimana dengan alasan perlindungan kode? Bukankah Packer dan Obfuscator jauh lebih melindungi kode dibandingkan Minifier? Ini semua adalah pilihan. Pada dasarnya setiap teknik kompresi masih tetap bisa menjaga agar file bisa dibaca oleh peramban. Ambil keputusan yang sekiranya memiliki kerugian terkecil berdasarkan tujuan.

Memperkecil Permintaan HTTP

Semakin banyak permintaan HTTP (HTTP Requests) yang terjadi, maka akan semakin lambat halaman termuat. Permintaan HTTP pada dasarnya hanyalah tentang seberapa banyak peramban menghubungi server untuk memanggil data. Cara mengecek permintaan yang terjadi sebenarnya sangat mudah. Perhatikan saja status bar pada peramban Anda saat halaman sedang dimuat:

Melihat Proses Transfer Data Melalui Status Bar
Melihat proses transfer data melalui bar status

Dari situ Anda bisa melihat mana data yang cepat diakses dan mana yang lebih lama diakses berdasarkan kecepatan perubahan status. Jika Anda sudah menemukan apa yang membuat situs Anda menjadi lambat, Anda bisa segera mengambil keputusan terhadap file yang berhubungan dengan itu. Apakah akan membuangnya atau mengubah pengurutan permintaan yang lebih lambat menuju ke level yang lebih rendah (tidak dinomorsatukan). Misalnya, dengan cara meletakkan file yang lebih lama termuat di sebelah bawah.

Usahakan untuk mengurangi permintaan HTTP dari situs pihak ke tiga sebanyak mungkin. Katakanlah kita memiliki sebuah blog yang dilengkapi dengan widget Facebook Like, Twitter Feed, Chatbox dan Disqus dalam satu halaman yang sama. Ditambah lagi foto-foto artikel dan gambar latar belakang yang diunggah di Photobucket, kode CSS yang disimpan di GitHub dan JavaScript yang disimpan di Google Code. Kita bisa mengatakan itu semua sebagai komponen permintaan situs pihak ke tiga, karena kita telah menyisipkan berbagai URL file yang disimpan di ruang penyimpanan lain ke dalam blog kita. Meskipun mereka semua hanya berupa file-file kecil yang umumnya berupa teks, namun saat Anda membuka halaman blog dimana file-file yang disertakan di dalamnya masih merupakan milik situs lain, itu tetap saja akan memiliki arti yang sama seperti halnya Anda sedang membuka semua situs tersebut secara bersamaan!

Menggabungkan Semua File Eksternal Sejenis

Menggabungkan semua file sejenis ke dalam sebuah file besar bisa menjadi solusi termudah untuk mengurangi permintaan HTTP. Artinya bahwa kita akan mengubah sesuatu yang tadinya seperti ini:

<link rel="stylesheet" href="style1.css">
<link rel="stylesheet" href="style2.css">
<link rel="stylesheet" href="style3.css">
<script src="script1.js"></script>
<script src="script2.js"></script>
<script src="script3.js"></script>

menjadi seperti ini:

<link rel="stylesheet" href="style-123.css">
<script src="script-123.js"></script>

Ini berlaku juga untuk JavaScript dan CSS internal. Meskipun mereka tidak memiliki hubungan dengan permintaan HTTP, namun mengurangi jumlah tag <style> dan <script> di dalam dokumen juga bisa mempermudah peramban dalam membaca dokumen (memperpendak jarak baca dan mengurangi pengulangan baca file dengan tipe yang sama):

<script>
function abc() {
   document.write('abc');
}
</script>
<script>
function def() {
   alert('def');
}
</script>
<script>
function ghi() {
   var c = confirm('ghi?');
   if(c) window.open('http://nama_blog.com');
}
</script>
<script>
$(function() {
    // DOM ready 1 ...
});
$(function() {
    // DOM ready 2 ...
});
$(function() {
    // DOM ready 3 ...
});
</script>
<script>
abc();
def();
ghi();
</script>
<style>#lorem {width:200px}</style>
<style>#ipsum {color:red}</style>
<style>#dolor {border:1px solid blue}</style>

Ubah semua susunan kode di atas menjadi seperti ini:

<style>
#lorem {width:200px}
#ipsum {color:red}
#dolor {border:1px solid blue}
</style>
<script>
function abc() {
   document.write('abc');
}
function def() {
   alert('def');
}
function ghi() {
   var c = confirm('ghi?');
   if(c) window.open('http://nama_blog.com');
}
$(function() {
    // DOM ready 1 ...
    // DOM ready 2 ...
    // DOM ready 3 ...
});
</script>
<script>
abc();
def();
ghi();
</script>

Meletakkan JavaScript di atas </body>

Ini memiliki arti bahwa kita meletakkan JavaScript sejauh mungkin dari sebelah atas dokumen. Hal ini disarankan untuk mencegah keterlambatan pemuatan kerangka HTML di bawahnya karena lambatnya proses muat JavaScript di atasnya. Dengan meletakkan JavaScript di bawah, maka setidaknya kita telah mengizinkan peramban untuk merayapi kerangka halaman terlebih dahulu sebelum kemudian sampai pada masa untuk memuat dan membaca JavaScript. Posisikan juga CSS lebih awal dibandingkan JavaScript sehingga pembentukan tubuh halaman akan dieksekusi terlebih dahulu dibandingkan pengerjaan JavaScript.

Tapi tunggu dulu! Meletakkan JavaScript di bagian bawah juga tidak sepenuhnya benar. Beberapa faktor bisa membuat mereka tidak bekerja. Selengkapnya bisa di baca di sini

Merasa Blog/Situs Anda Sudah Cukup Cepat?

Jangan senang dulu. Mungkin itu karena Anda telah mengunjungi situs web Anda berkali-kali, yang juga berarti bahwa cache dari situs Anda masih tersimpan di dalam komputer. Sekarang coba Anda hapus semua cache yang ada kemudian muat ulang halaman situs Anda kembali:

Menghapus Cache
Menghapus Cache

Saat cache sudah terhapus, maka Anda akan merasakan kecepatan situs Anda yang sesungguhnya seperti halnya saat pengunjung Anda membuka situs Anda.

Tentunya akan terasa sedikit lebih lambat. Itu juga merupakan kesimpulan sederhana mengenai pertanyaan bodoh tentang mengapa saat kita pertama kali mengunjungi sebuah situs terasa begitu berat, namun saat kita telah menjadi langganan mereka, semuanya berubah menjadi lebih cepat.

Pembicaraan optimasi ini sepertinya lebih banyak berputar di sekitar JavaScript dan CSS saja. Ya, karena Saya pikir pembicaraan selain itu masih bisa dipahami seperti apa adanya. Saya hanya ingin menuliskan sesuatu yang seringkali menjadi sumber kesalahpahaman. Punya tambahan?

Labels: , , ,

Tuesday, June 5, 2012

Jimp · A jQuery Tooltip for Image Preview

Jimp is a lightweight jQuery tooltip plugin for image preview. Very responsive to the viewport position and easy in installation.

Jimp - A jQuery Tooltip for Image Preview

Jimp adalah plugin jQuery untuk menampilkan gambar dalam tooltip yang sangat responsif terhadap posisi layar dan mudah dalam hal instalasi. Selalu bisa menjaga posisi dirinya pada daerah yang terlihat. Mendukung URL kustom tanpa harus mengeset pengaturan plugin secara manual. Jimp akan menentukan sendiri URL mana yang akan diambil sebagai penampil gambar:

Lihat Demo Download

Dasar Penggunaan

Wajib menggunakan jQuery versi 1.7 atau di atasnya. Susun jQuery, Jimp dan kode CSS seperti ini. Letakkan semuanya di atas kode </head>

<link rel="stylesheet" media="screen" href="css/jimp.css" />
<script src="js/jquery-1.7.min.js"></script>
<script src="js/jimp.js"></script>
<script>
$(function() {
    $('#example a').jimp();
});
</script>

Markup HTML

Ada dua metode yang bisa Anda lakukan untuk mengaktifkan plugin ini pada elemen. Pertama, mengarahkan tautan langsung kepada URL gambar. Ke dua, mengarahkan tautan ke sebuah halaman situs, kemudian mengeset nilai tooltip dengan URL gambar yang disimpan di dalam atribut data-preview:

<a href="large-image.jpg" title="Your Title"><img src="thumbnail.jpg" alt="thumbnail" /></a>
<a href="page-url.html" data-preview="large-image.jpg" title="Your Title">This is an example link!</a>

Konfigurasi Plugin

Secara default ada beberapa opsi di dalam plugin ini yang bisa Anda sesuaikan sebagai pengaturan lanjutan:

$(function() {
    $('#example a').jimp({
        width: 40, // default width of the tooltip before image loaded
        height: 40, // default height of the tooltip before image loaded
        resizeSpeed: 200, // resize speed of container
        fadeSpeed: 400, // fade speed of image
        delay: 1000, // mouseenter delay before excecuting
        offsetTop: 20, // tooltip offset top from pointer
        offsetLeft: 20, // tooltip offset left from pointer
        linkText: 'save', // save button label
        closeText: '&#215', // close button label
        hideOnOut: false, // if true, then when pointer mouse leave from image/link target, the tooltip will hidden and back to it's normal size
        hideOnChange: false // if true, then when pointer mouse leave from image/link target (and then enter to the other target), the tooltip will hidden and back to it's normal size
    });
});
Opsi Keterangan
width Digunakan untuk menentukan lebar tooltip saat pertama kali tampil
height Digunakan untuk menentukan tinggi tooltip saat pertama kali tampil
resizeSpeed Digunakan untuk menentukan kecepatan animasi perubahan ukuran tooltip gambar
fadeSpeed Digunakan untuk menentukan kecepatan efek fading pada gambar
delay Waktu penundaan sebelum perintah untuk menampilkan tooltip dieksekusi
offsetTop Jarak atas tooltip terhadap pointer
offsetLeft Jarak kiri tooltip terhadap pointer
closeText Label untuk tombol tutup [x]
linkText Label untuk tombol penyimpan gambar
hideOnOut Jika true, maka tooltip akan tersembunyi ketika pointer mouse meninggalkan gambar/link target
hideOnChange Jika true, maka ketika pointer mouse meninggalkan gambar/link target dan kemudian memasuki target yang lain, tooltip akan tersembunyi dan kembali ke ukuran normal.
Jika false, tooltip akan terus tampak bersamaan dengan perpindahan target dan akan mengubah ukurannya seiring keberhasilan pointer dalam menemukan target yang baru.

Ini adalah plugin pertama Saya. Mungkin memang masih ada beberapa deklarasi kode yang tidak begitu efisien, tapi setidaknya Saya sudah bisa memastikan bahwa plugin ini bebas dari kesalahan penulisan. Saya sudah mengetesnya pada Web Console, semua peramban mayor dan validasi JavaScript di JSBin dan JSFiddle. Untuk sementara semuanya akan Saya simpan di Google berhubung Saya belum begitu mahir soal GitHub. Situs jQuery Plugin juga saat ini masih dalam perbaikan. Ke depannya mungkin akan muncul berbagai plugin baru yang meskipun tidak semenarik plugin-plugin yang sudah ada, tapi bisa dikatakan cukup bermanfaat untuk kalangan umum.

Labels: , , ,

Friday, June 1, 2012

Solusi untuk Masalah Blog Bertema Komik

Menambahkan Sistem Navigasi pada Komik
Menambahkan Sistem Navigasi pada Komik

Ini soal pengalaman pribadi. Selama Saya berkeliling mencari situs-situs penyedia baca komik online, ada tiga macam jenis penyajian yang Saya temukan. Pertama, situs tersebut menunjukkan setiap halaman komik tunggal pada satu posting. Sehingga jika kita ingin membaca cerita pada halaman berikutnya, kita harus mengeklik tombol Next atau semacamnya untuk memuat posting baru yang berisi satu halaman komik berikutnya.

Ke dua, situs tersebut akan menyajikan semua halaman komik dalam satu posting, sehingga kita bisa membaca dari awal sampai akhir tanpa harus berpindah-pindah halaman. Namun resikonya adalah kita akan kehilangan begitu banyak waktu hanya untuk menunggu semua halaman komik termuat pada posting tersebut. Belum lagi jika situs yang kita kunjungi telah dipenuhi berbagai macam iklan yang akan semakin memperlambat proses muat halaman. Tidak berbeda dengan konsep penyajian pertama, karena saat kita berpindah-pindah halaman kita harus menunggu bermenit-menit hanya untuk memuat satu gambar saja.

Bagi Saya ini tidak efektif, mengingat yang para pembaca butuhkan pada dasarnya hanyalah halaman komik dan bukan halaman situs secara keseluruhan. Jika waktu kita dihabiskan hanya untuk menunggu seluruh halaman situs termuat, padahal yang sebenarnya kita butuhkan adalah halaman komik, maka resikonya adalah kita akan kehilangan masa-masa mendalami alur cerita.

Solusinya biasanya adalah dengan cara memuat halaman komik secara bertahap. Artinya adalah kita hanya akan melihat satu halaman komik saja pada satu posting, namun saat kita mengeklik tombol halaman berikutnya, kita tidak akan dibawa menuju ke halaman/posting situs baru, melainkan hanya akan berdiam diri pada satu tempat dan menunggu gambar baru selesai termuat pada satu tempat yang sama.

Saya tidak tahu pasti apa teknik yang mereka gunakan untuk itu. Mungkin AJAX. Tapi Saya pikir itu terlalu berlebihan. Kita bisa menggunakan Lightbox! Hanya saja, lightbox yang satu ini tidak menampilkan gambar di atas tabir hitam seperti lightbox pada umumnya. Kita akan menampilkan gambar tepat di atas navigasi, dengan begitu suasana membaca akan tetap terasa seperti halnya saat kita membaca komik biasa.

Konsep dasarnya masih sama seperti tutorial pembuatan lightbox yang pernah Saya tuliskan di sini. Yaitu kita akan menembak URL gambar pada tautan ke dalam elemen <img> setiap kali aksi klik dilakukan:

$('ul a').click(function() {
    $('div').html('<img src="' + this.href + '" alt="Loading..."/>');
    return false;
});

Lihat Konsep

Di sini kita akan membuat markup yang berbeda agar setiap tautan tampak sebagai navigasi halaman berangka, dan gambar yang termuat akan ditampilkan di atasnya sebagai halaman komik tunggal:

Lihat Hasil Akhir

Markup HTML

Yang kita perlukan tidak banyak. Kita hanya akan membuat daftar tautan yang mengarah ke setiap unit halaman komik (halaman komik adalah gambar). Jadi buat saja seperti ini:

<ul class="img-gallery" data-width="750" data-height="1088">
  <li><a href="img/01.png">Judul Halaman 1</a></li>
  <li><a href="img/02.png">Judul Halaman 2</a></li>
  <li><a href="img/03.png">Judul Halaman 3</a></li>
  <li><a href="img/04.png">Judul Halaman 4</a></li>
</ul>

Kelas img-gallery digunakan sebagai identitas, sehingga jQuery hanya akan memanipulasi elemen daftar yang memiliki kelas img-gallery saja. data-width digunakan untuk menentukan lebar halaman komik, data-height digunakan untuk menentukan tinggi halaman komik. Ini diperlukan karena kita akan membuat aplikasi yang tidak hanya bisa digunakan untuk menangani satu komik saja per satu posting tapi juga beberapa komik sekaligus dalam ukuran yang berbeda-beda. Dalam satu halaman.

Memulai Manipulasi

Pertama-tama kita akan membungkus grup tautan halaman komik di atas dengan elemen yang kita beri nama .img-show:

$('.img-gallery').each(function() {
    $(this).addClass('img-nav').wrap('<div class="img-show"></div>');
});

Saya juga menambahkan kelas baru bernama .img-nav. Itu akan kita gunakan sebagai selektor CSS untuk mengubah tampilan daftar menjadi tampak sebagai navigasi halaman. Sehingga markup HTML akan menjadi seperti ini:

<div class="img-show">
  <ul class="img-gallery img-nav" data-width="750" data-height="1088">
    <li><a href="img/01.png">Judul Halaman 1</a></li>
    <li><a href="img/02.png">Judul Halaman 2</a></li>
    <li><a href="img/03.png">Judul Halaman 3</a></li>
    <li><a href="img/04.png">Judul Halaman 4</a></li>
  </ul>
</div>

Setelah itu sisipkan kontainer kosong yang akan kita gunakan sebagai tempat untuk meletakkan gambar:

$('.img-gallery').each(function() {
    $(this).addClass('img-nav').wrap('<div class="img-show"></div>');
    $(this).parents('.img-show').prepend('<div class="img-holder"></div>');
});

Sehingga markup HTML akan menjadi seperti ini:

<div class="img-show">
  <div class="img-holder"></div>
  <ul class="img-gallery img-nav" data-width="750" data-height="1088">
    <li><a href="img/01.png">Judul Halaman 1</a></li>
    <li><a href="img/02.png">Judul Halaman 2</a></li>
    <li><a href="img/03.png">Judul Halaman 3</a></li>
    <li><a href="img/04.png">Judul Halaman 4</a></li>
  </ul>
</div>

Pada dasarnya itu saja markup yang diperlukan untuk membuat aplikasi komik digital ini. Selebihnya hanya tinggal menentukan ukuran dan perintah. Sekarang kita ringkas semua kode yang terlalu panjang, dan ambil data lebar dan tinggi halaman yang sudah kita simpan di dalam atribut data-width dan data-height:

$('.img-gallery').each(function() {
    var w = $(this).data('width'),
        h = $(this).data('height');
    $(this).addClass('img-nav').wrap('<div class="img-show" style="width:' + w + 'px;"></div>');
    var $parent = $(this).parents('.img-show');
    $parent.prepend('<div class="img-holder" style="height:' + h + 'px;"></div>');
});

Sehingga hasilnya akan menjadi seperti ini:

<div class="img-show" style="width:750px;">
  <div class="img-holder" style="height:1088px;"></div>
  <ul class="img-gallery img-nav" data-width="750" data-height="1088">
    <li><a href="img/01.png">Judul Halaman 1</a></li>
    <li><a href="img/02.png">Judul Halaman 2</a></li>
    <li><a href="img/03.png">Judul Halaman 3</a></li>
    <li><a href="img/04.png">Judul Halaman 4</a></li>
  </ul>
</div>

Dimensi halaman sudah tercipta, sekarang saatnya mengubah setiap item tautan menjadi navigasi berangka. Kita akan menggunakan jQuery .each() untuk merayapi semua elemen tautan satu persatu kemudian menyisipkan angka sesuai dengan urutannya, memindah semua teks judul halaman pada masing-masing tautan ke dalam atribut title. Tapi sebelum itu kita atur dulu agar saat halaman pertama kali dibuka, gambar pada navigasi halaman pertama bisa tampil tanpa diperintah:

$('.img-gallery').each(function() {
    var w = $(this).data('width'),
        h = $(this).data('height');
    $(this).addClass('img-nav').wrap('<div class="img-show" style="width:' + w + 'px;"></div>');
    var $firstNav = $('li:first a', this), // Mendapatkan tautan pertama dari semua tautan dalam daftar
        current = $firstNav.attr('href'), // Mendapatkan nilai href tautan pertama untuk ditampilkan sebagai gambar pada saat pertama kali komik diakses
        $parent = $(this).parents('.img-show');
    $firstNav.addClass('active'); // Menambahkan kelas active pada tautan pertama
    $parent.prepend('<div class="img-holder" style="height:' + h + 'px;"></div>');
    // Sisipkan gambar (halaman komik) pada elemen .img-holder...
    // dengan nilai src yang diambil dari atribut href tautan pertama
    $parent.find('.img-holder').addClass('loading').html('<img class="transparent" src="' + current + '" alt="Loading..."/>');
});

Kelas .loading ditambahkan untuk mengaktifkan CSS khusus yang akan memberikan latar berupa gambar animasi loading:

<div class="img-show" syle="width:750px;">
  <div class="img-holder loading" style="height:1088px;">
    <img class="transparent" src="img/01.png" alt="Loading..."/>
  </div>
  <ul class="img-gallery img-nav" data-width="750" data-height="1088">
    <li><a class="active" href="img/01.png">Judul Halaman 1</a></li>
    <li><a href="img/02.png">Judul Halaman 2</a></li>
    <li><a href="img/03.png">Judul Halaman 3</a></li>
    <li><a href="img/04.png">Judul Halaman 4</a></li>
  </ul>
</div>
.img-show .img-holder.loading {
  background:white url('img/loading.gif') no-repeat 50% 300px;
}

Atur tampilan gambar yang berhasil ditambahkan dengan tingkat transparasi sebesar 0, sehingga gambar akan tampak menghilang dan memperlihatkan latar animasi loading di belakangnya:

$parent.find('img.transparent').css('opacity', 0);

Saat ini gambar masih memuat, saat gambar telah benar-benar berhasil termuat, animasikan tingkat transparasi menuju 1 (opaque) sehingga efek fading akan tercipta setiap kali gambar selesai termuat:

$parent.find('img.transparent').css('opacity', 0).load(function() {
    $parent.find('.img-holder').removeClass('loading'); // Singkirkan kelas loading pada kontainer saat gambar telah berhasil dimuat
    $(this).animate({opacity:1}, 400); // Animasikan nilai transparasi dari 0 menuju 1
});

Menyisipkan Angka-Angka

Untuk menyisipkan angka-angka, kita gunakan .each() untuk merayapi semua tautan yang ada kemudian ganti semua teks di dalamnya menjadi angka sesuai dengan urutannya. Di sini Saya juga akan memindah teks asli pada masing-masing tautan ke dalam atribut title, sehingga tidak akan ada yang sia-sia:

$('.img-gallery').each(function() {
    var w = $(this).data('width'),
        h = $(this).data('height');
    $(this).addClass('img-nav').wrap('<div class="img-show" style="width:' + w + 'px;"></div>');
    var $firstNav = $('li:first a', this),
        current = $firstNav.attr('href'),
        $parent = $(this).parents('.img-show');
    $firstNav.addClass('active');
    $parent.prepend('<div class="img-holder" style="height:' + h + 'px;"></div>');
    $parent.find('.img-holder').addClass('loading').html('<img class="transparent" src="' + current + '" alt="Loading..."/>');
    $('a', this).each(function(i) {
        i = i+1; // Proses pengurutan dalam JavaScript dimulai dari nol, untuk mengangkat nilai awal pengurutan, naikkan satu tingkat!
        $(this).attr('title', $(this).text()); // Pindahkan semua teks (judul halaman) pada tautan menjadi nilai atribut title pada setiap tautan
        $(this).html(i); // Terakhir, sisipkan nomor urut pada masing-masing tautan
    });
});

Sehingga hasilnya akan menjadi seperti ini:

<div class="img-show" syle="width:750px;">
  <div class="img-holder loading" style="height:1088px;">
    <img class="transparent" src="img/01.png" alt="Loading..."/>
  </div>
  <ul class="img-gallery img-nav" data-width="750" data-height="1088">
    <li><a class="active" href="img/01.png" title="Judul Halaman 1">1</a></li>
    <li><a href="img/02.png" title="Judul Halaman 2">2</a></li>
    <li><a href="img/03.png" title="Judul Halaman 3">3</a></li>
    <li><a href="img/04.png" title="Judul Halaman 4">4</a></li>
  </ul>
</div>

Memasukkan Perintah

Sekarang kita tambahkan perintah pada setiap navigasi halaman. Jika navigasi halaman diklik, sisipkan nilai href dari navigasi halaman tersebut ke dalam elemen <img>, kemudian atur efek animasi seperti pada efek animasi yang kita buat sebelum ini:

$('a', this).each(function(i) {
    i = i+1;
    $(this).attr("title", $(this).text());
    $(this).html(i);
}).on("click", function() {
    var $activeNav = $(this).parents('.img-gallery').find('a.active'),
        $activeParent = $(this).parents('.img-show');
    // Bergantian mengganti kelas setiap kali klik pada navigasi
    $activeNav.removeClass('active');
    $(this).addClass('active').parents('.img-show').find('.img-holder').html('<img class="transparent" src="' + this.href + '" alt="Loading..."/>');
    $parent.find('.img-holder').addClass('loading').find('img.transparent').css('opacity', 0).load(function() {
        $(this).removeClass('loading').find('img').animate({opacity:1}, 400);
    });
    return false;
});

Lebar dan Tinggi Halaman yang Berbeda

Tidak semua halaman komik memiliki tinggi dan lebar yang sama. Terkadang mereka juga bisa tampak sebagai gambar lebar berbentuk persegi panjang mendatar. Oleh karena itu menganimasikan tinggi dan lebar kontainer juga penting. Kita bisa mendapatkan lebar dan tinggi gambar saat gambar telah termuat, sehingga kita misa menganimasikan ukuran kontainer sesuai dengan ukuran gambar yang tampil. Modifikasi dilakukan pada saat fungsi telah menunjukkan bahwa gambar sudah termuat:

$('a', this).each(function(i) {
    i = i+1;
    $(this).attr("title", $(this).text());
    $(this).html(i);
}).on("click", function() {
    var $activeNav = $(this).parents('.img-gallery').find('a.active'),
        $activeParent = $(this).parents('.img-show');
    $activeNav.removeClass('active');
    $(this).addClass('active').parents('.img-show').find('.img-holder').html('<img class="transparent" src="' + this.href + '" alt="Loading..."/>');
    $parent.find('.img-holder').addClass('loading').find('img.transparent').css('opacity', 0).load(function() {
        // Animasikan lebar dan tinggi kontainer setelah gambar termuat
        $parent.animate({width:$(this).width()}, 600).find('.img-holder').animate({height:$(this).height()}, 600, function() {
            // Setelah animasi tinggi dan lebar selesai dijalankan,
            // set nilai transparasi gambar menjadi opaque
            $(this).removeClass('loading').find('img').animate({opacity:1}, 400);
        });
    });
    return false;
});

Membuat Halaman Meloncat ke Posisi yang Tepat

Saat menekan tombol navigasi, pada dasarnya kita sedang berada pada posisi halaman paling bawah. Akan sangat merepotkan jika pembaca harus menggulung layar ke atas kembali setiap kali gambar baru termuat, jadi kita buat saja agar halaman meloncat ke atas setiap kali navigasi diklik. Kita gunakan jQuery .scrollTop() untuk urusan ini:

$('a', this).each(function(i) {
    i = i+1;
    $(this).attr("title", $(this).text());
    $(this).html(i);
}).on("click", function() {
    var $activeNav = $(this).parents('.img-gallery').find('a.active'),
        $activeParent = $(this).parents('.img-show');
    $activeNav.removeClass('active');
    $('html, body').scrollTop($activeParent.offset().top-40);
    $(this).addClass('active').parents('.img-show').find('.img-holder').html('<img class="transparent" src="' + this.href + '" alt="Loading..."/>');
    $parent.find('.img-holder').addClass('loading').find('img.transparent').css('opacity', 0).load(function() {
        // Animasikan lebar dan tinggi kontainer setelah gambar termuat
        $parent.animate({width:$(this).width()}, 600).find('.img-holder').animate({height:$(this).height()}, 600, function() {
            // Setelah animasi tinggi dan lebar selesai dijalankan,
            // set nilai transparasi gambar menjadi opaque
            $(this).removeClass('loading').find('img').animate({opacity:1}, 400);
        });
    });
    return false;
});

Selesai! Sisanya tinggal merapikan dan memidah semua hal yang berhubungan dengan durasi animasi ke dalam variabel baru, sehingga proses modifikasi kecepatan animasi menjadi lebih mudah dilakukan.


Kode Lengkap

jQuery

$(function() {
    $('.img-gallery').each(function() {
        var w = $(this).data("width"),
            h = $(this).data("height"),
            viewport = $('html, body'),
            fadeSpeed = 400, // Kecepatan efek fading
            resizeSpeed = 600; // Kecepatan efek pelebaran/penyusutan
        $(this).addClass('img-nav').wrap('<div class="img-show" style="width:' + w + 'px;"></div>');
        var $firstNav = $('li:first a', this),
            current = $firstNav.attr('href'),
            $parent = $(this).parents('.img-show');
        $firstNav.addClass('active');
        $parent.prepend('<div class="img-holder" style="height:' + h + 'px;"></div>');
        $parent.find('.img-holder').addClass('loading').html('<img class="transparent" src="' + current + '" alt="Loading..."/>');
        $parent.find('img.transparent').css('opacity', 0).load(function() {
            $parent.animate({width:$(this).width()}, resizeSpeed).find('.img-holder').animate({height:$(this).height()}, resizeSpeed, function() {
                $(this).removeClass('loading').find('img').animate({opacity:1}, fadeSpeed);
            });
        });
        
        $('a', this).each(function(i) {
            i = i+1;
            $(this).attr("title", $(this).text());
            $(this).html(i);
        }).on("click", function() {
            var $activeNav = $(this).parents('.img-gallery').find('a.active'),
                $activeParent = $(this).parents('.img-show');
            $activeNav.removeClass('active');
            viewport.scrollTop($activeParent.offset().top-40);
            $(this).addClass('active').parents('.img-show').find('.img-holder').html('<img class="transparent" src="' + this.href + '" alt="Loading..."/>');
            $parent.find('.img-holder').addClass('loading').find('img.transparent').css('opacity', 0).load(function() {
                $parent.animate({width:$(this).width()}, resizeSpeed).find('.img-holder').animate({height:$(this).height()}, resizeSpeed, function() {
                    $(this).removeClass('loading').find('img').animate({opacity:1}, fadeSpeed);
                });
            });
            return false;
        });

    });
});

CSS

.img-show {
  width:400px;
  margin:50px auto;
  background-color:black;
  border:2px solid black;
  -webkit-box-shadow:0 1px 3px rgba(0,0,0,.2);
  -moz-box-shadow:0 1px 3px rgba(0,0,0,.2);
  box-shadow:0 1px 3px rgba(0,0,0,.2);
  position:relative;
  overflow:hidden;
}

.img-show .img-holder {
  background-color:white;
}

.img-show .img-holder.loading {
  background:white url('data:image/gif;base64,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') no-repeat 50% 160px;
}

.img-show .img-holder img {
  display:block;
}

.img-show .img-nav {
  margin:0;
  padding:0;
  overflow:hidden;
}

.img-show .img-nav li {
  margin:2px 2px 0 0;
  padding:0;
  float:left;
  display:inline;
  list-style:none;
}

.img-nav li a {
  display:block;
  background-color:#ccc;
  color:black;
  padding:3px 7px;
  font:normal normal 12px/normal Georgia,"URW Bookman L",Serif;
  font-style:italic;
  text-decoration:none;
}

.img-nav li a.active {
  background-color:#900;
  color:white;
}

Dasar Kerangka

<ul class="img-gallery" data-width="750" data-height="1000">
    <li><a href="img/01.png">Judul Halaman 1</a></li>
    <li><a href="img/02.png">Judul Halaman 2</a></li>
    <li><a href="img/03.png">Judul Halaman 3</a></li>
</ul>

Labels: , , ,