Сетка миниатюр с возможностью расширенного представления
В последнее время поиск изображений через Google несколько преобразился. Сегодня мы рассмотрим, каким образом можно организовать подобный функционал. Идея заключается в отображении более крупного изображения при клике на его миниатюру, а также вывод названия, описания и ссылки.
Ключевым моментом будет вычисление нужного размера полного изображения и перемещение страницы на нужную позицию. При показе крупного изображения, мы также оставим видимым его миниатюру, а весь оставшийся контент накроем блоком серого цвета. Также мы не будем использовать крупные изображения, так что на крупных мониторах могут образоваться свободные области.
Итак, давайте начнём!
HTML
Для начала, нам необходимо отобразить сетку изображений. Для этого мы воспользуемся ненумерованным списком. Каждый элемент списка, будет содержать элемент ссылки с несколькими очень важными атрибутами:
<ul id="og-grid" class="og-grid">
<li>
<a href="http://cargocollective.com/jaimemartinez/" data-largesrc="/images/1.jpg" data-title="Azuki bean" data-description="Swiss chard pumpkin bunya nuts maize plantain aubergine napa cabbage soko coriander sweet pepper water spinach winter purslane shallot tigernut lentil beetroot.">
<img src="/images/thumbs/1.jpg" alt="img01"/>
</a>
</li>
<li>
<a href="http://cargocollective.com/jaimemartinez/" data-largesrc="/images/2.jpg" data-title="Veggies sunt bona vobis" data-description="Komatsuna prairie turnip wattle seed artichoke mustard horseradish taro rutabaga ricebean carrot black-eyed pea turnip greens beetroot yarrow watercress kombu.">
<img src="/images/thumbs/2.jpg" alt="img02"/>
</a>
</li>
<li><!-- ... --></li>
<!-- ... -->
</ul>
Значение атрибута href будет использоваться при формировании ссылки (также будет работать с отключённым JavaScript). В атрибутах data-largesrc содержится адрес полного изображения, data-title - название, data-description - описание.
При клике на миниатюру более крупное представление будет раскрываться чуть ниже, поэтому его html код мы поместим в тот же элемент списка, прямо за элементом ссылки:
<li>
<a href="http://cargocollective.com/jaimemartinez/" data-largesrc="/images/2.jpg" data-title="Veggies sunt bona vobis" data-description="Komatsuna prairie turnip wattle seed artichoke mustard horseradish taro rutabaga ricebean carrot black-eyed pea turnip greens beetroot yarrow watercress kombu.">
<img src="/images/thumbs/2.jpg" alt="img02"/>
</a>
<div class="og-expander">
<div class="og-expander-inner">
<span class="og-close"></span>
<div class="og-fullimg">
<div class="og-loading"></div>
<img src="/images/2.jpg">
</div>
<div class="og-details">
<h3>Veggies sunt bona vobis</h3>
<p>Komatsuna prairie turnip wattle seed artichoke mustard horseradish taro rutabaga ricebean carrot black-eyed pea turnip greens beetroot yarrow watercress kombu.</p>
<a href="http://cargocollective.com/jaimemartinez/">Visit website</a>
</div>
</div>
</div>
</li>
Теперь давайте всё это дело оформим.
CSS
Заметка: в данных листингах вы не найдёте css префиксов для разных браузеров. Полный код можно найти в исходниках, которые доступны для скачивания.
Итак, давайте начнём с самой сетки. Она будет размером во весь экран, текст будет располагаться по центру. Также будут отцентрированы и все миниатюры, благодаря данной записи “display: inline-block”:
.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;
}
Ссылки и изображения будут отображаться как блоки. Также для данных элементов сбросим некоторые стили:
.og-grid li > a,
.og-grid li > a img {
border: none;
outline: none;
display: block;
position: relative;
}
При клике на элемент сетки, мы добавим специальный класс og-expanded. Также к панели прикрепим знак стрелки, чтоб знать к какой миниатюре относится описание.
.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;
}
Раскрывающийся блок будет позиционироваться абсолютно, и у него также будет класс og-expander. Изначально его высота будет равна 0, а опция overflow равна hidden, т.е. элемент будет скрыт.
.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%;
}
Знак закрытия панели будет формироваться из псевдо-элементов (двух повёрнутых линий):
.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% в ширину, а также прикреплены друг к другу:
.og-fullimg,
.og-details {
width: 50%;
float: left;
height: 100%;
overflow: hidden;
position: relative;
}
Опции изображения max-width выставим 100%, чтобы его размеры автоматически подгонялись под размеры контейнера.
.og-details {
padding: 0 40px 0 20px;
}
.og-fullimg {
text-align: center;
}
.og-fullimg img {
display: inline-block;
max-height: 100%;
max-width: 100%;
}
Теперь давайте добавим стилей для текста и ссылки:
.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;
}
Отображение загрузки изображения будет располагаться в том же контейнере, где и картинка. Данный элемент мы реализуем средствами CSS: создадим круг и три тени, затем анимируем изменение цвета заливки:
.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. В этом случае, размер миниатюры и так велик:
@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%; }
}
Ну, а теперь давайте оживим нашу сетку с помощью JavaScript.
JavaScript
Для начала, давайте закэшируем некоторые данные:
// списки элементов
var $grid = $( '#og-grid' ),
// элементы
$items = $grid.children( 'li' ),
// индекс текущего раскрытого элемента
current = -1,
// позиция (top) раскрывшегося элемента
previewPos = -1,
// количество пикселей, на которое нужно прокрутить страницу
scrollExtra = 0,
// значение margin раскрытого элемента (между изображением и следующим элементов в строке)
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'
};
Теперь можно загрузить все миниатюры в сетку. После этого мы сможем записать размеры каждого элемента сетки, размер экрана и назначить несколько событий:
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() };
}
Функция showPreview предназначена для инициализации объекта Preview, который в последствии будет раскрываться, показывая название, описание и крупное изображение. Если данный объект уже создан, то мы просто обновим его внутренние данные (в зависимости от того, какое действие совершил пользователь: закрыл представление, кликнул на другую миниатюру и так далее).
Для проверки клика по миниатюре, которая находится в том же ряду с уже кликнутой (раскрытой), воспользуемся значением смещения top данных элементов:
function showPreview( $item ) {
var preview = $.data( this, 'preview' ),
// смещение сверху
position = $item.data( 'offsetTop' );
scrollExtra = 0;
// если представление полного изображения существует и previewPos отличается (разные строки в сетке), закроем панель
if( typeof preview != 'undefined' ) {
// не в одной и той же строке
if( previewPos !== position ) {
// если position > previewPos, то берём в расчёт текущую высоту панели представления для скроллинга (смещения) страницы
if( position > previewPos ) {
scrollExtra = preview.height;
}
hidePreview();
}
// если в той же строке
else {
preview.update( $item );
return false;
}
}
// обновляем previewPos
previewPos = position;
// инициализируем новую панель для представления элемента, по которому был осуществлён клик
preview = $.data( this, 'preview', new Preview( $item ) );
// раскрыть представление
preview.open();
}
Объект Preview будет ссылаться на элемент, который отображается на текущем этапе (Preview.$item), а также будет иметь доступ к индексу раскрытого элемента (Preview.expandedIdx). Благодаря этим значениям, мы можем определить, закрывать панель представления (при клике по другой миниатюре из другой строки сетки) или оставить панель и только обновить данные (при клике по миниатюре в той же строке сетки).
// объект preview
function Preview( $item ) {
this.$item = $item;
this.expandedIdx = this.$item.index();
this.create();
this.update();
}
Теперь, когда объект Preview готов, можем взяться за код, который будет выводить детализированную информацию об изображении:
create : function() {
// создаём структуру:
this.$title = $( '<h3></h3>' );
this.$description = $( '<p></p>' );
this.$href = $( '<a href="#">Visit website</a>' );
this.$details = $( '<div class="og-details"></div>' ).append( this.$title, this.$description, this.$href );
this.$loading = $( '<div class="og-loading"></div>' );
this.$fullimage = $( '<div class="og-fullimg"></div>' ).append( this.$loading );
this.$closePreview = $( '<span class="og-close"></span>' );
this.$previewInner = $( '<div class="og-expander-inner"></div>' ).append( this.$closePreview, this.$fullimage, this.$details );
this.$previewEl = $( '<div class="og-expander"></div>' ).append( this.$previewInner );
// прикрепляем html код к элементу
this.$item.append( this.getEl() );
// задаём элементу настройки перемещения
if( support ) {
this.setTransition();
}
}
Функция update будет задействована для обновления информации в панели представления:
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/>' ).load( function() {
self.$loading.hide();
self.$largeImg = $( this ).fadeIn( 350 );
self.$fullimage.append( self.$largeImg );
} ).attr( 'src', eldata.largesrc );
}
}
Далее мы должны рассчитать размер панели представления полного изображения. Его высота будет равна значению высоты окна - высота элемента сетки. Для того чтобы избежать непредвиденных ситуаций, также зададим значение minHeight.
После того как панелька раскроется, нам нужно сместить немного страницу:
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() {
// сместить страницу
// вариант 1 : высота превью + высота элемента (помещается в размер окна)
// вариант 2 : высота превью + высота элемента (не помещается в размер окна). Получившийся размер меньше размера окна.
// вариант 3 : высота превью + высота элемента (не помещается в размер окна). Получившийся размер больше размера окна.
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 );
}
При закрытии панели необходимо поставить всё на свои места и удалить скрытый html из DOM.
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;
}
Надеюсь, данный урок и его результат будут вам полезны!
Источник: http://feedproxy.google.com/~r/ruseller/CdHX/~3/2q35KhfBxWE/lessons.php
|
В последнее время поиск изображений через Google несколько преобразился. Сегодня мы рассмотрим, каким образом можно организовать подобный функционал. Идея заключается в отображении более крупного |
РэдЛайн, создание сайта, заказать сайт, разработка сайтов, реклама в Интернете, продвижение, маркетинговые исследования, дизайн студия, веб дизайн, раскрутка сайта, создать сайт компании, сделать сайт, создание сайтов, изготовление сайта, обслуживание сайтов, изготовление сайтов, заказать интернет сайт, создать сайт, изготовить сайт, разработка сайта, web студия, создание веб сайта, поддержка сайта, сайт на заказ, сопровождение сайта, дизайн сайта, сайт под ключ, заказ сайта, реклама сайта, хостинг, регистрация доменов, хабаровск, краснодар, москва, комсомольск |
Дайджест новых статей по интернет-маркетингу на ваш email
Новые статьи и публикации
- 2026-03-04 » Скорость, ИИ и человекоцентричность: каким должен быть сайт в 2026 году
- 2026-03-03 » Как искусственный интеллект меняет таргетированную рекламу
- 2026-03-03 » Основные киберугрозы для бизнеса: 5 способов потерять (и сохранить) данные компании
- 2026-03-03 » Главные тренды веб-дизайна 2026 года: от гиперминимализма до кибербрутализма
- 2026-03-03 » Искусственный интеллект в маркетинге: помощник, а не замена человеку
- 2026-02-26 » Нулевая позиция в поиске: как на нее попасть и зачем это нужно
- 2026-02-26 » Как выбрать подрядчика для сайта и не попасть на мошенников
- 2026-02-26 » Инклюзивный клиентский опыт: как сделать бизнес доступным для всех и повысить конверсию
- 2026-02-26 » ESG-принципы: что это такое и как бизнесу внедрять их в свою работу
- 2026-02-26 » Почему в 2026 году маркетологу не стоит бояться искусственного интеллекта
- 2026-02-22 » No-code vs Профессиональная разработка: выстрелит ли Tilda в 2026 году?
- 2026-02-22 » Почему малый бизнес проигрывает в контекстной рекламе и при чем тут структура сайта
- 2026-02-22 » Куда уходит скорость: как мы теряем посетителей из-за одного "тяжелого" шрифта
- 2026-02-22 » Дарк-паттерны (Dark Patterns) в интерфейсах: когда манипуляция клиентом выходит боком
- 2026-02-22 » Голосовой поиск и веб: готов ли ваш сайт к разговору с Алисой и Марусей?
- 2026-02-22 » Микроанимация и UX/UI: как движение элементов влияет на конверсию
- 2026-02-22 » ИИ в веб-аналитике: как нейросети предсказывают отток клиентов до того, как они уйдут
- 2026-02-22 » Темная сторона шаблонов: почему сайт на готовом решении может угробить ваш бизнес
- 2026-02-22 » Зеленый хостинг и экология в IT: тренд или необходимость?
- 2026-02-22 » Веб-доступность (Accessibility): почему ваш сайт теряет до 20% клиентов и штрафует сам себя
- 2026-02-12 » Экономика фриланса vs веб-студии: скрытые издержки и риски при заказе сайта «у знакомого разработчика»
- 2026-02-12 » Инструменты аналитики помимо Google Analytics
- 2026-02-12 » Юридические аспекты владения сайтом
- 2026-02-12 » Сравниваем популярные CRM-системы для интеграции с сайтом
- 2026-02-12 » Эволюция интерфейсов: от CLI к GUI, к VUI и далее
- 2026-02-12 » Контент-стратегия после обновления Google Helpful Content
- 2026-02-12 » Headless-архитектура: модный тренд или необходимость для вашего бизнеса?
- 2026-02-12 » Мифы о кибербезопасности для малого и среднего бизнеса
- 2026-02-12 » Как Core Web Vitals влияют не только на SEO, но и на конверсию?
- 2026-02-12 » PWA vs Нативное приложение: что выбрать малому бизнесу в 2026?
"Не пытайтесь перехитрить поисковые машины - надежность и доверие ценятся в сфере поискового маркетинга куда больше." |
Мы создаем сайты, которые работают! Профессионально обслуживаем и продвигаем их , а также по всей России и ближнему зарубежью с 2006 года!
Как мы работаем
Заявка
Позвоните или оставьте заявку на сайте.
Консультация
Обсуждаем что именно Вам нужно и помогаем определить как это лучше сделать!
Договор
Заключаем договор на оказание услуг, в котором прописаны условия и обязанности обеих сторон.
Выполнение работ
Непосредственно оказание требующихся услуг и работ по вашему заданию.
Поддержка
Сдача выполненых работ, последующие корректировки и поддержка при необходимости.

Мы создаем практически любые сайты от продающих страниц до сложных, высоконагруженных и нестандартных веб приложений! Наши сайты это надежные маркетинговые инструменты для успеха Вашего бизнеса и увеличения вашей прибыли! Мы делаем красивые и максимально эффектные сайты по доступным ценам уже много лет!
Комплексный подход это не просто продвижение сайта, это целый комплекс мероприятий, который определяется целями и задачами поставленными перед сайтом и организацией, которая за этим стоит. Время однобоких методов в продвижении сайтов уже прошло, конкуренция слишком высока, чтобы была возможность расслабиться и получать \ удерживать клиентов из Интернета, просто сделав сайт и не занимаясь им...
Мы оказываем полный комплекс услуг по сопровождению сайта: информационному и техническому обслуживанию и развитию Интернет сайтов.
Контекстная реклама - это эффективный инструмент в интернет маркетинге, целью которого является увеличение продаж. Главный плюс контекстной рекламы заключается в том, что она работает избирательно.