Реальное применение свойства clip для формирования визуального эффекта

В предыдущем уроке мы рассказали о замечательном свойстве CSS clip и функции rect().  Теперь рассмотрим практическое применение описанного свойства. Создадим прелестный и простой эффект для скрытия части содержания и вывода его полностью на весь экран.

Мы продемонстрируем использование свойства CSS clip для формирования плавного перехода при нажатии на прямоугольном элементе.  Идея заключается в выводе покрывающего слоя так, как будто он скрывается под соответствующим элементом. Нажатие на элемент удаляет его с экрана, открывая покрывающий слой, который разворачивается на все окно.

Сначала создаем список пунктов, оформленных в стиле прямоугольников Metro:

Каждый прямоугольник содержит элемент (покрывающий слой), который позиционируется фиксировано. Данный элемент в действительности раскрыт над все страницей, но для него установлена полная прозрачность. При нажатии на прямоугольник используется  clip: rect() для обрезки соответствующей части внутренного фиксированного элемента. Затем происходит анимация расширения обрезанной части до полных ширины и высоты покрывающего слоя, которые соответствуют размерам окна просмотра:

Нажатие на кнопке закрытия вызовет реверс эффекта, и покрывающий слой свернется до размеров пункта списка и исчезнет.

 

Разметка HTML

Для прямоугольников будем использовать неупорядоченный список. Каждый пункт списка имеет класс иконки и опциональный класс “span”, который управляет шириной прямоугольника. Внутрь мы добавляем текст и элемент div покрывного слоя. Покрывной слой имеет структуру табличного шаблона. Для примера мы выбрали тему погоды, поэтому на покрывном слое представлена имитация прогноза на 7 дней. Каждый столбец дня имеет несколько элементов span, которые используются для указания дня недели, иконки погоды и температуры.

<ul id="rb-grid" class="rb-grid clearfix">
 
    <li class="icon-clima-1 rb-span-2">
 
        <h3>Лиссабон</h3>
        <span class="rb-temp">21°C</span>
 
        <div class="rb-overlay">
            <span class="rb-close">close</span>
            <div class="rb-week">
                <div><span class="rb-city">Лиссабон</span><span class="icon-clima-1"></span><span>21°C</span></div>
                <div><span>Пн</span><span class="icon-clima-1"></span><span>19°C</span></div>
                <div><span>Вт</span><span class="icon-clima-2"></span><span>19°C</span></div>
                <div><span>Ср</span><span class="icon-clima-2"></span><span>18°C</span></div>
                <div><span>Чт</span><span class="icon-clima-2"></span><span>17°C</span></div>
                <div><span>Пт</span><span class="icon-clima-1"></span><span>19°C</span></div>
                <div><span>Сб</span><span class="icon-clima-1"></span><span>22°C</span></div>
                <div><span>Вс</span><span class="icon-clima-1"></span><span>18°C</span></div>
            </div>
        </div>
         
    </li>
 
    <li class="icon-clima-2">
        <h3>Париж</h3><span class="rb-temp">11°C</span>
        <div class="rb-overlay">
            <!-- ... -->
        </div>
    </li>
 
    <li><!-- ... --></li>
 
    <!-- ... -->
 
</ul>

 

CSS

В тексте урока опущены префиксы браузеров. Полный код можно посмотреть в исходниках.

Неупорядоченный список центрируется в родительском элементе и для него удаляются стили списка:

.rb-grid {
    list-style: none;
    text-align: center;
    margin: 0 auto;
}

Пункты списка имеют плавающую ширину и высоту в 15em. Они будут сдвигаться влево:

.rb-grid li {
    width: 24%;
    height: 15em;
    margin: 0.5%;
    background: #8CC7DF;
    color: #fff;
    display: block;
    float: left;
    padding: 1.6em;
    cursor: pointer;
    position: relative;
}

Существует три различных ширины для пунктов нашей сетки. По умолчанию один вариант 24%, а остальные два определяются так:

.rb-grid li.rb-span-2 {
    width: 49%;
}
 
.rb-grid li.rb-span-4 {
    width: 99%;
}

Определяем заголовок с названием города:

.rb-grid li h3 {
    font-size: 2.6em;
    font-weight: 100;
}

Включаем файл  CSS для иконок, которые будут использоваться на странице. Это шрифт Climacons (автор Adam Whitcroft). Вы можете просмотреть файл climacons.css, чтобы понять,какие иконки мы включили. Для добавления иконок с помощью псевдо элемента мы используем класс иконок.. В нашей сетке они будут позиционироваться абсолютно в правом нижнем углу и выводиться с небольшим усечением:

.rb-grid li[class^="icon-"]:before,
.rb-grid li[class*=" icon-"]:before {
    font-size: 10em;
    position: absolute;
    display: block;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    line-height: 3;
    opacity: 0.4;
    text-align: right;
    pointer-events: none;
}

Температура будет полупрозрачной и мы используем переход для установки уровня видимости:

.rb-temp {
    display: block;
    font-size: 2em;
    opacity: 0.5;
    transition: all 0.3s ease-in-out;
}

При наведении на пункт списка мы просто увеличим непрозрачность:

.rb-grid li:hover .rb-temp {
    opacity: 1;
}

Теперь рассмотрим важный элемент div покрывного слоя. Конечный вид будет распространяться на весь экран, поэтому установим ширину и высоту 100%. Он должен располагаться поверх всего на экране, поэтому определяем для него фиксированное позиционирование. Начальное значение свойства z-index устанавливаем равным -1. Таким образом покрывной слой помещается за содержанием страницы, а установка непрозрачности равной 0 делает его невидимым:

.rb-overlay {
    opacity: 0;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    transition: all 0.4s ease;
    z-index: -1;
    pointer-events: none;
    cursor: default;
}

Это исходное состояние покрывного слоя. Как только мы нажмем на пункте списка, нужно установить правильные значения функции rect() для свойства clip и расширяем покрывной слой с помощью анимации.

Рассмотрим остальные стили.

Каждый покрывной слой имеет небольшую кнопку “закрыть”, которая позиционируется в верхнем правом углу.

.rb-close {
    position: absolute;
    top: 0.4em;
    right: 0.4em;
    width: 2em;
    height: 2em;
    text-indent: -9000px;
    cursor: pointer;
    z-index: 1000;
}
 
.rb-close:before {
    content: 'x';
    font-weight: 100;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    font-size: 3em;
    line-height: 0.6;
    text-align: center;
    text-indent: 0px;
}

Контейнер для столбца имеет класс rb-week (хотя мы также включаем колонку текущей погоды). Нужно установить ширину и высоту 100%, чтобы можно было определять высоту и ширину элементов наследников:

.rb-week {
    width: 100%;
    height: 100%;
}

Колонки будут иметь ширину 10% (за исключением первой, которая имеет ширину 30%) и будут смещаться влево:

.rb-week > div {
    width: 10%;
    height: 100%;
    float: left;
    position: relative;
    padding: 3% 0;
}
 
.rb-week > div:first-child {
    width: 30%;
}

У нас есть восемь колонок: 7 из них занимают 70% (7 раз по 10%), а восьмая - 30%.

Каждый элемент span имеет высоту 30% и небольшой отступ:

.rb-week span {
    padding: 5% 0;
    font-size: 2em;
    font-weight: 100;
    display: block;
    margin: auto 0;
    height: 30%;
    width: 100%;
    line-height: 0.8;
}

Элемент span для имени города имеет специальный стиль с более легким шрифтом:

.rb-week span.rb-city {
    font-weight: 700;
    padding: 1% 10%;
    font-size: 1em;
    line-height: 1.2;
}

Иконки имеют увеличенный размер шрифта и нужно сбросить его вес, который изменяется другими правилами:

.rb-week [class^="icon-"]:before {
    font-size: 2.5em;
    font-weight: normal;
}

Колонка текущей погоды будет почти прозрачной:

.rb-week > div:first-child [class^="icon-"] {
    opacity: 0.1;
}

Теперь определим разные цвета фона для каждого прямоугольника и каждой колонки в покрывном слое.

У нас есть 11 пунктов списка:

/* Цвета */
 
/* Сетка */
.rb-grid li:nth-child(1) { background: #3399CC; }
.rb-grid li:nth-child(2) { background: #33CCCC; }
.rb-grid li:nth-child(3) { background: #996699; }
.rb-grid li:nth-child(4) { background: #C24747; }
.rb-grid li:nth-child(5) { background: #e2674a; }
.rb-grid li:nth-child(6) { background: #FFCC66; }
.rb-grid li:nth-child(7) { background: #99CC99; }
.rb-grid li:nth-child(8) { background: #669999; }
.rb-grid li:nth-child(9) { background: #CC6699; }
.rb-grid li:nth-child(10) { background: #339966; }
.rb-grid li:nth-child(11) { background: #666699; }

И каждый покрывной слой имеет восемь колонок:

/* Колонки в покрывном слое */
.rb-grid li:nth-child(1) .rb-week > div:nth-child(1) { background: #3399CC; }
.rb-grid li:nth-child(1) .rb-week > div:nth-child(2) { background: #2D87B4; }
.rb-grid li:nth-child(1) .rb-week > div:nth-child(3) { background: #297AA3; }
.rb-grid li:nth-child(1) .rb-week > div:nth-child(4) { background: #256E93; }
.rb-grid li:nth-child(1) .rb-week > div:nth-child(5) { background: #216283; }
.rb-grid li:nth-child(1) .rb-week > div:nth-child(6) { background: #1D5672; }
.rb-grid li:nth-child(1) .rb-week > div:nth-child(7) { background: #184962; }
.rb-grid li:nth-child(1) .rb-week > div:nth-child(8) { background: #143D52; }
 
.rb-grid li:nth-child(2) .rb-week > div:nth-child(1) { background: #33CCCC; }
.rb-grid li:nth-child(2) .rb-week > div:nth-child(2) { background: #2DB4B4; }
.rb-grid li:nth-child(2) .rb-week > div:nth-child(3) { background: #29A3A3; }
.rb-grid li:nth-child(2) .rb-week > div:nth-child(4) { background: #259393; }
.rb-grid li:nth-child(2) .rb-week > div:nth-child(5) { background: #218383; }
.rb-grid li:nth-child(2) .rb-week > div:nth-child(6) { background: #1D7272; }
.rb-grid li:nth-child(2) .rb-week > div:nth-child(7) { background: #186262; }
.rb-grid li:nth-child(2) .rb-week > div:nth-child(8) { background: #145252; }
 
/* ... */

…и так lzk всех 11 прямоугольников.

И в завершении воспользуемся медиа запросами для маленьких экранов.

Когда пространство ограничено, то не нужно выводить прямоугольники в сетке.

@media screen and (max-width: 63.125em) {
     
    .rb-grid li,
    .rb-grid li.rb-span-2,
    .rb-grid li.rb-span-4 {
        width: 100%;
        height: 10em;
        text-align: left;
    }
 
    .rb-grid li[class^="icon-"]:before,
    .rb-grid li[class*=" icon-"]:before {
        font-size: 6em;
        left: auto;
        right: 0;
        line-height: 2.5;
    }
 
    .rb-grid li > div {
        text-align: center;
    }
}

Колонки покрывного слоя и текст в них будут формироваться с помощью плагина FitText, поэтому шаблон не будет меняться драматически.

 

JavaScript

Начнем с кеширования элементов и инициализации переменных:

var $items = $( '#rb-grid > li' ),
    transEndEventNames = {
        'WebkitTransition' : 'webkitTransitionEnd',
        'MozTransition' : 'transitionend',
        'OTransition' : 'oTransitionEnd',
        'msTransition' : 'MSTransitionEnd',
        'transition' : 'transitionend'
    },
 
    // Название перехода и события
    transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ],
 
    // Элементы window и body
    $window = $( window ),
    $body = $( 'BODY' ),
 
    // Поддержка переходов
    supportTransitions = Modernizr.csstransitions,
 
    // Индекс текущего элемента
    current = -1,
 
    // Ширина и высота окна
    winsize = getWindowSize();

Сначала мы применяем плагин jQuery FitText к элементам текста колонок в покровным слое, чтобы масштабировать текст в соответствии с размером экрана.

Затем привязываем событие click к пунктам и кнопки закрытия.

Также нужно получить текущее значение для ширины и высоты окна и привязать событие resize к элементу окна.

function init( options ) {      
    // Применяем плагин fittext
    $items.find( 'div.rb-week > div span' ).fitText( 0.3 ).end().find( 'span.rb-city' ).fitText( 0.5 );
    initEvents();
}

Когда происходит нажатие на пункте, запускаются два перехода для соответствующего покровного элемента. Первый применяет свойство clip, которое обрезает покровный слой точно по размерам прямоугольника. Также покровный слой будет изменять прозрачность. Второй переход выполняет анимацию расширения покровного слоя на все окно. Для первого перехода значения должны соответсвовать положению и размерам пункта списка. Мы получаем значения вызывая функцию “getItemLayoutProp”. Для второго слоя нам нужна только ширина и высота окна для определения правильных значений.

Также нужно принять во внимание два момента. Первое, мы скрываем прокрутку страницы в промежуточном состоянии, так как не нужно, чтобы кто-нибудь прокручивал страницу до завершения перехода (расширения покровного слоя). Второе покровной слой имеет свойство z-index с большим значением, чтобы всегда оставаться сверху, и свойство pointer-events имеет значение auto, чтобы покровной слой принимал события click. Если переходы не поддерживаются, первое состояние пропускается и покровной слой сразу расширяется до полного размера.

function initEvents() {
     
    $items.each( function() {
 
        var $item = $( this ),
            $close = $item.find( 'span.rb-close' ),
            $overlay = $item.children( 'div.rb-overlay' );
 
        $item.on( 'click', function() {
 
            if( $item.data( 'isExpanded' ) ) {
                return false;
            }
            $item.data( 'isExpanded', true );
            // Сохраняем текущий индекс пункта
            current = $item.index();
 
            var layoutProp = getItemLayoutProp( $item ),
                clipPropFirst = 'rect(' + layoutProp.top + 'px ' + ( layoutProp.left + layoutProp.width ) + 'px ' + ( layoutProp.top + layoutProp.height ) + 'px ' + layoutProp.left + 'px)',
                clipPropLast = 'rect(0px ' + winsize.width + 'px ' + winsize.height + 'px 0px)';
 
            $overlay.css( {
                clip : supportTransitions ? clipPropFirst : clipPropLast,
                opacity : 1,
                zIndex: 9999,
                pointerEvents : 'auto'
            } );
 
            if( supportTransitions ) {
                $overlay.on( transEndEventName, function() {
 
                    $overlay.off( transEndEventName );
 
                    setTimeout( function() {
                        $overlay.css( 'clip', clipPropLast ).on( transEndEventName, function() {
                            $overlay.off( transEndEventName );
                            $body.css( 'overflow-y', 'hidden' );
                        } );
                    }, 25 );
 
                } );
            }
            else {
                $body.css( 'overflow-y', 'hidden' );
            }
 
        } );
 
        ...
 
    } );
 
    ...
 
}
 
function getItemLayoutProp( $item ) {
         
    var scrollT = $window.scrollTop(),
        scrollL = $window.scrollLeft(),
        itemOffset = $item.offset();
 
    return {
        left : itemOffset.left - scrollL,
        top : itemOffset.top - scrollT,
        width : $item.outerWidth(),
        height : $item.outerHeight()
    };
 
}

При нажатии кнопки "закрыть" все происходит в обратном порядке:

function initEvents() {
     
    $items.each( function() {
 
        ...
 
        $close.on( 'click', function() {
 
            $body.css( 'overflow-y', 'auto' );
 
            var layoutProp = getItemLayoutProp( $item ),
                clipPropFirst = 'rect(' + layoutProp.top + 'px ' + ( layoutProp.left + layoutProp.width ) + 'px ' + ( layoutProp.top + layoutProp.height ) + 'px ' + layoutProp.left + 'px)',
                clipPropLast = 'auto';
 
            // Сбрасывает текущее значение
            current = -1;
 
            $overlay.css( {
                clip : supportTransitions ? clipPropFirst : clipPropLast,
                opacity : supportTransitions ? 1 : 0,
                pointerEvents : 'none'
            } );
 
            if( supportTransitions ) {
                $overlay.on( transEndEventName, function() {
 
                    $overlay.off( transEndEventName );
                    setTimeout( function() {
                        $overlay.css( 'opacity', 0 ).on( transEndEventName, function() {
                            $overlay.off( transEndEventName ).css( { clip : clipPropLast, zIndex: -1 } );
                            $item.data( 'isExpanded', false );
                        } );
                    }, 25 );
 
                } );
            }
            else {
                $overlay.css( 'z-index', -1 );
                $item.data( 'isExpanded', false );
            }
 
            return false;
 
        } );
 
    } );
 
    ...
 
}

Готово!

Источник: http://feedproxy.google.com/~r/ruseller/CdHX/~3/1HAjyTPJdek/lessons.php

Читать комменты и комментировать

Добавить комментарий / отзыв



Защитный код
Обновить

Реальное применение свойства clip для формирования визуального эффекта | | 2013-01-27 13:40:00 | | Статьи Web-мастеру | | В предыдущем уроке мы рассказали о замечательном свойстве CSS clip и функции rect().  Теперь рассмотрим практическое применение описанного свойства. Создадим прелестный и простой эффект для скрытия | РэдЛайн, создание сайта, заказать сайт, разработка сайтов, реклама в Интернете, продвижение, маркетинговые исследования, дизайн студия, веб дизайн, раскрутка сайта, создать сайт компании, сделать сайт, создание сайтов, изготовление сайта, обслуживание сайтов, изготовление сайтов, заказать интернет сайт, создать сайт, изготовить сайт, разработка сайта, web студия, создание веб сайта, поддержка сайта, сайт на заказ, сопровождение сайта, дизайн сайта, сайт под ключ, заказ сайта, реклама сайта, хостинг, регистрация доменов, хабаровск, краснодар, москва, комсомольск |
 
Поделиться с друзьями: