Сетка миниатюр с предосмотром изображений
В последнее время интернет гигант Google стал на путь модернизма, и весьма преобразил свои ресурсы, а именно поиск изображений. Поиск стал более отзывчивым к пользователю, с приятным интерфейсом и продуманными деталями. Основным преимуществом является реакция изображений на нажатие мышки, в результате чего, мы получим выпадающий список с увеличенным изображением, его заголовком, описанием и возможностью перейти на ресурс с изображением. В данном уроке мы рассмотрим как это можно реализовать у себя на сайте.
Ключевым аспектом будет вычисление необходимого размера оригинального изображения, ведь нам необходимо указать стрелкой на просматриваемую миниатюру, кроме этого мы будем использовать блок закрашенный серым цветом, его, конечно, можно изменить на свой вкус.
Шаг 1. HTML
Для начала нам необходимо создать разметку для сетки изображений, для этого нам понадобится ненумерованный список. Кроме этого каждый элемент будет содержать ссылки и атрибуты:
1 2 3 4 5 6 7 8 9 10 11 12 |
</pre> <ul class="og-grid" id="og-grid"> <li><a href="#" rel="nofollow" data-largesrc="images/1.jpg" data-title="Azuki bean" data-description="Описание."> <img alt="img01" src="images/thumbs/1.jpg" /> </a></li> <li><a href="#" rel="nofollow" data-largesrc="images/2.jpg" data-title="Описание."> <img alt="img02" src="images/thumbs/2.jpg" /> </a></li> <li></li> </ul> <pre> |
Мы рассмотрели базовую разметку, теперь нам необходимо организовать структуру которая будет при нажатии на миниатюру:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
</pre> <ul> <li> <a href="Ссылка" data-largesrc="images/2.jpg" data-title="Описание."> <img alt="img02" src="images/thumbs/2.jpg" /> </a> <div class="og-expander"> <div class="og-expander-inner"> <div class="og-fullimg"> <div class="og-loading"></div> <img alt="" src="images/2.jpg" /></div> <div class="og-details"> <h3>Заголовок</h3> Описание. <a href="#">Перейти на сайт</a></div> </div> </div></li> </ul> <pre> |
С разметкой мы разобрались, перейдем к следующему шагу.
Шаг 2. CSS
Для начала нам необходимо определить стили сетки, она будет во всю ширину экрана, кроме этого нам необходимо отцентрировать миниатюры, сделаем это мы с помощью “display: inline-block”:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.og-grid { list-style: none; padding: 20px 0; margin: 0 auto; text-align: center; width: 100%; } .og-grid li { display: inline-block; margin: 10px 5px 0 5px; vertical-align: top; height: 250px; } |
Нам необходимо отображать ссылки как блоки:
1 2 3 4 5 6 7 |
.og-grid li > a, .og-grid li > a img { border: none; outline: none; display: block; position: relative; } |
Теперь добавим знак стрелки, который будет появляться когда активируем большой контейнер:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.og-grid li.og-expanded > a::after { top: auto; border: solid transparent; content: " "; height: 0; width: 0; position: absolute; pointer-events: none; border-bottom-color: #ddd; border-width: 15px; left: 50%; margin: -20px 0 0 -15px; } |
Блок в сером цвете будет иметь абсолютное позиционирование, кроме этого его высота, изначально, будет равна 0, а опция overflow равна hidden- элемент будет скрыт.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
.og-expander { position: absolute; background: #ddd; top: auto; left: 0; width: 100%; margin-top: 10px; text-align: left; height: 0; overflow: hidden; } .og-expander-inner { padding: 50px 30px; height: 100%; } |
Добавим псевдоэлементы для закрытия контейнера, он будет состоять из двух линий:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
.og-close { position: absolute; width: 40px; height: 40px; top: 20px; right: 20px; cursor: pointer; } .og-close::before, .og-close::after { content: ''; position: absolute; width: 100%; top: 50%; height: 1px; background: #888; transform: rotate(45deg); } .og-close::after { transform: rotate(-45deg); } .og-close:hover::before, .og-close:hover::after { background: #333; } |
Контейнеры для изображения и описания будут 50% в ширину, а также прикреплены друг к другу:
1 2 3 4 5 6 7 8 |
.og-fullimg, .og-details { width: 50%; float: left; height: 100%; overflow: hidden; position: relative; } |
Теперь определим базовые стили для текста и ссылки:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
.og-details h3 { font-weight: 300; font-size: 52px; padding: 40px 0 10px; margin-bottom: 10px; } .og-details p { font-weight: 400; font-size: 16px; line-height: 22px; color: #999; } .og-details a { font-weight: 700; font-size: 16px; color: #333; text-transform: uppercase; letter-spacing: 2px; padding: 10px 20px; border: 3px solid #333; display: inline-block; margin: 30px 0 0; outline: none; } .og-details a::before { content: '\2192'; display: inline-block; margin-right: 10px; } .og-details a:hover { border-color: #999; color: #999; } |
Добавим элемент для загрузки изображений, он будет достаточно просто, кроме этого установим теми и немного закруглим:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
.og-loading { width: 20px; height: 20px; border-radius: 50%; background: #ddd; box-shadow: 0 0 1px #ccc, 15px 30px 1px #ccc, -15px 30px 1px #ccc; position: absolute; top: 50%; left: 50%; margin: -25px 0 0 -25px; animation: loader 0.5s infinite ease-in-out both; } @keyframes loader { 0% { background: #ddd; } 33% { background: #ccc; box-shadow: 0 0 1px #ccc, 15px 30px 1px #ccc, -15px 30px 1px #ddd; } 66% { background: #ccc; box-shadow: 0 0 1px #ccc, 15px 30px 1px #ddd, -15px 30px 1px #ccc; } } |
Добавим несколько медиа-запросов, они необходимы для правильного отображения если размер экрана меньше 650px:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@media screen and (max-width: 830px) { .og-expander h3 { font-size: 32px; } .og-expander p { font-size: 13px; } .og-expander a { font-size: 12px; } } @media screen and (max-width: 650px) { .og-fullimg { display: none; } .og-details { float: none; width: 100%; } } |
Со стилями мы разобрались, перейдем к последнему шагу.
Шаг 3. JavaScript
Для начала нам необходимо определить базовые переменные:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
// списки элементов var $grid = $( '#og-grid' ), // сами элементы $items = $grid.children( 'li' ), // индекс текущего элемента current = -1, // позиция раскрывшегося элемента previewPos = -1, // количество пикселей, на которое нужно прокрутить страницу scrollExtra = 0, marginExpanded = 10, $window = $( window ), winsize, $body = $( 'html, body' ), // события трансформации transEndEventNames = { 'WebkitTransition' : 'webkitTransitionEnd', 'MozTransition' : 'transitionend', 'OTransition' : 'oTransitionEnd', 'msTransition' : 'MSTransitionEnd', 'transition' : 'transitionend' }, transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ], support = Modernizr.csstransitions, // базовые настройки settings = { minHeight : 500, speed : 350, easing : 'ease' }; |
Нам необходимо загрузить все изображения, после этого мы сможем записать все размеры изображений:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
function init( config ) { // настройки settings = $.extend( true, {}, settings, config ); // загрузить все изображения $grid.imagesLoaded( function() { // сохраняем размер и смещение элементов saveItemInfo( true ); // получаем размер окна getWinSize(); // инициализация событий initEvents(); } ); } // сохраняем верхнее смещение элемента и его высоту function saveItemInfo( saveheight ) { $items.each( function() { var $item = $( this ); $item.data( 'offsetTop', $item.offset().top ); if( saveheight ) { $item.data( 'height', $item.height() ); } } ); } function getWinSize() { winsize = { width : $window.width(), height : $window.height() }; } |
Функция update нам будет необходима для обновления информации в панели представления:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
update : function( $item ) { // обновить настройки элемента if( $item ) { this.$item = $item; } // если раскрыта, убираем класс "og-expanded" с текущего элемента if( current !== -1 ) { var $currentItem = $items.eq( current ); $currentItem.removeClass( 'og-expanded' ); this.$item.addClass( 'og-expanded' ); // позиция Preview объекта this.positionPreview(); } // обновить текущий индекс current = this.$item.index(); // обновить контент представления var $itemEl = this.$item.children( 'a' ), eldata = { href : $itemEl.attr( 'href' ), largesrc : $itemEl.data( 'largesrc' ), title : $itemEl.data( 'title' ), description : $itemEl.data( 'description' ) }; this.$title.html( eldata.title ); this.$description.html( eldata.description ); this.$href.attr( 'href', eldata.href ); var self = this; // удалить изображение из панели представления if( typeof self.$largeImg != 'undefined' ) { self.$largeImg.remove(); } // загрузить новое изображение и добавить в панель if( self.$fullimage.is( ':visible' ) ) { this.$loading.show(); $( '<img alt="" />' ).load( function() { self.$loading.hide(); self.$largeImg = $( this ).fadeIn( 350 ); self.$fullimage.append( self.$largeImg ); } ).attr( 'src', eldata.largesrc ); } } |
Страница должна немного смещаться вниз, когда блок будет развернут:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
open : function() { setTimeout( $.proxy( function() { // задать высоту блока this.setHeights(); // сместить позицию страницы this.positionPreview(); }, this ), 25 ); } setHeights : function() { var self = this, onEndFn = function() { if( support ) { self.$item.off( transEndEventName ); } self.$item.addClass( 'og-expanded' ); }; this.calcHeight(); this.$previewEl.css( 'height', this.height ); this.$item.css( 'height', this.itemHeight ).on( transEndEventName, onEndFn ); if( !support ) { onEndFn.call(); } } calcHeight : function() { var heightPreview = winsize.height - this.$item.data( 'height' ) - marginExpanded, itemHeight = winsize.height; if( heightPreview < settings.minHeight ) { heightPreview = settings.minHeight; itemHeight = settings.minHeight + this.$item.data( 'height' ) + marginExpanded; } this.height = heightPreview; this.itemHeight = itemHeight; } positionPreview : function() { // сместить страницу var position = this.$item.data( 'offsetTop' ), previewOffsetT = this.$previewEl.offset().top - scrollExtra, scrollVal = this.height + this.$item.data( 'height' ) + marginExpanded <= winsize.height ? position : this.height < winsize.height ? previewOffsetT - ( winsize.height - this.height ) : previewOffsetT; $body.animate( { scrollTop : scrollVal }, settings.speed ); } |
При закрытии блока нам необходимо вернуть всё на свои места:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
close : function() { var self = this, onEndFn = function() { if( support ) { $( this ).off( transEndEventName ); } self.$item.removeClass( 'og-expanded' ); self.$previewEl.remove(); }; setTimeout( $.proxy( function() { if( typeof this.$largeImg !== 'undefined' ) { this.$largeImg.fadeOut( 'fast' ); } this.$previewEl.css( 'height', 0 ); // текущий раскрытый элемент (может отличаться от this.$item) var $expandedItem = $items.eq( this.expandedIdx ); $expandedItem.css( 'height', $expandedItem.data( 'height' ) ).on( transEndEventName, onEndFn ); if( !support ) { onEndFn.call(); } }, this ), 25 ); return false; } |
Вот и все. Готово!
Материал взят из зарубежного источника. И представлен исключительно в ознакомительных целях.
Читайте также:
Опубликовал Cooper 06.04.2013 в 19:10, в категории jQuery. Вы можете следить за комментариями через RSS 2.0. Вы можете перейти в конец записи и оставить комментарий. Пинги запрещены. |