• 18
  • апр
  • 2024
В новостях:
Веб-программирование

Меню с образцами при помощи CSS3 и jQuery

В данном уроке мы расскажем как создать анимированное меню с образцами при помощи CSS3 и JavaScript. Идея состоит в том, чтобы показать набор образцов и при нажатии на отдельный образец, мы будем сдвигать другие образцы с целью показа выбранного.

Меню с образцами при помощи CSS3 и jQuery
Поделиться в соцсетях:

В данном уроке мы расскажем как создать анимированное меню с образцами при помощи CSS3 и JavaScript. Идея состоит в том, чтобы показать набор образцов и при нажатии на отдельный образец, мы будем сдвигать другие образцы с целью показа выбранного.

Пожалуйста, обратите внимание: результат этого урока будет работать, как задумано, только в браузерах, которые поддерживают соответствующие свойства CSS.

В этом уроке мы будем использовать иконки шрифта, созданного при помощи Fontello.

Мы будем опускать префиксы браузеров в примерах кода в этой статье, но вы, конечно, можете найти их в исходных файлах.

HTML-разметка

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

<div id="sb-container" class="sb-container">
  <div>
    <span class="sb-icon icon-cog"></span>
    <h4><span>All Settings</span></h4>
  </div>
  <div>
    <span class="sb-icon icon-flight"></span>
    <h4><span>User Modes</span></h4>
  </div>  
  <div>
    <!-- ... -->
  </div>  
  <!-- ... -->
  <div>
    <h4><span>Profile</span></h4>
    <h5><span>We ♥ color</span></h5>
  </div>
</div><!-- sb-container -->

Последний раздел не будет иметь иконку, но вместо этого там будут два заголовка h4 и h5. Последний раздел будет нашей "обложкой" и самым верхним слоем в нашем наборе образцов.

Давайте теперь посмотрим на стили.

CSS

Во-первых, давайте определим стили для контейнера содержащего образцы. Мы сделаем его такой же ширины, как и один из образцов (хотя они занимают больше места), так что мы можем легко центрировать его:

.sb-container {
    position: relative;
    width: 150px;
    height: 400px;
    margin: 30px auto 0 auto;
}

Наша цель заключается в создании набора образцов, состоящего из отдельных панелей. Каждая из них будет вращаться с помощью CSS transform (JS). Итак, давайте зададим образцам ширину и высоту, а также абсолютное позиционирование. В исходном состоянии все образцы уложены друг на друга. Свойство transform-origin будут определять, как наши образцы будут сменять друг друга. Так как мы хотим использовать левый нижний угол, то мы установили значение 25% и 90%. Свойство backface-visibility hidden поможет скрыть лишний текст при повороте:

.sb-container div {
    position: absolute;
    top: 0;
    left: 0;
    width: 130px;
    background: #fff;
    height: 400px;
    border-radius: 5px;
    cursor: pointer;
    text-align: center;
    background-image: url(../images/fabric.png);
    transform-origin: 25% 90%;
    backface-visibility: hidden;
}

Давайте определим различные цвета для фона и тени для каждого блока:

.sb-container div:nth-child(1){
    background-color: #ea2a29;
    box-shadow: -1px -1px 3px rgba(0,0,0,0.1), 1px 1px 1px rgba(0,0,0,0.1);
}
.sb-container div:nth-child(2){
    background-color: #f16729;
    box-shadow: -1px -1px 3px rgba(0,0,0,0.1), 2px 2px 1px rgba(0,0,0,0.1);
}
.sb-container div:nth-child(3){
    background-color: #f89322;
    box-shadow: -1px -1px 3px rgba(0,0,0,0.1), 3px 3px 2px rgba(0,0,0,0.2);
}
.sb-container div:nth-child(4){
    background-color: #ffcf14;
    box-shadow: -1px -1px 3px rgba(0,0,0,0.1), 4px 4px 4px rgba(0,0,0,0.2);
}
.sb-container div:nth-child(5){
    background-color: #ffea0d;
    box-shadow: -1px -1px 3px rgba(0,0,0,0.1), 5px 5px 6px rgba(0,0,0,0.3);
}
.sb-container div:nth-child(6){
    background-color: #87b11d;
    box-shadow: -1px -1px 3px rgba(0,0,0,0.1), 6px 6px 8px rgba(0,0,0,0.3);
}
.sb-container div:nth-child(7){
    background-color: #008253;
    box-shadow: -1px -1px 3px rgba(0,0,0,0.1), 7px 7px 10px rgba(0,0,0,0.4);
}
.sb-container div:nth-child(8){
    background-color: #3277b5;
    box-shadow: -1px -1px 3px rgba(0,0,0,0.1), 8px 8px 12px rgba(0,0,0,0.4);
}
.sb-container div:nth-child(9){
    background-color: #4c549f;
    box-shadow: -1px -1px 3px rgba(0,0,0,0.1), 9px 9px 14px rgba(0,0,0,0.4);
}
.sb-container div:nth-child(10){
    background-color: #764394;
    box-shadow: -1px -1px 3px rgba(0,0,0,0.1), 10px 10px 16px rgba(0,0,0,0.4);
}
.sb-container div:nth-child(11){
    background-color: #ca0d86;
    box-shadow: -1px -1px 3px rgba(0,0,0,0.1), 11px 11px 18px rgba(0,0,0,0.4);
}

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

Последний образец будет служить в качестве обложки, поэтому мы зададим ему особый фон и тень:

.sb-container div:last-child {
    background: #645b5c url(../images/cover.jpg) repeat center center;
    box-shadow:
        -1px -1px 3px rgba(0,0,0,0.2),
        12px 12px 20px rgba(0,0,0,0.6),
        inset 2px 2px 0 rgba(255, 255, 255, 0.1);
}

Давайте добавим небольшие медные заклепки. Для этого мы будем использовать псевдо-класс :after. Они будут иметь градиент и тень, чтобы выглядеть так, как будто они сделаны из металла. Положение зависит от свойства transform-origin,  поэтому устанавливаем медную заклепку в левый нижний угол:

.sb-container div:last-child:after {
    content: '';
    position: absolute;
    bottom: 15px;
    left: 15px;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: #dddddd;
    background: linear-gradient(135deg, #dddddd 0%,#58535e 48%,#889396 100%);
    box-shadow: -1px -1px 1px rgba(0,0,0,0.5), 1px 1px 1px rgba(255,255,255,0.1);
}

Давайте зададим стили для заголовков:

.sb-container div h4 {
    color: rgba(255,255,255,0.9);
    text-shadow: 1px 1px 1px rgba(0,0,0,0.2);
    font-weight: 700;
    font-size: 16px;
    text-transform: uppercase;
    border-top: 1px dashed rgba(0,0,0,0.1);
    border-bottom: 1px dashed rgba(0,0,0,0.1);
    margin: 5px;
    padding: 5px;
    user-select: none;
}
.sb-container div:last-child h4 {
    background: rgba(0,0,0,0.2);
    box-shadow: 0 1px 1px rgba(255,255,255,0.1);
}

Большой заголовок на обложке будет поворачиваться в правильное положение. Это зависит от размера такста, так что если вы используете другой текст, то вы должны будете изменить эти значения:

.sb-container div:last-child h5 {
    font-size: 50px;
    white-space: nowrap;
    text-align: left;
    margin: 0;
    padding: 0;
    position: absolute;
    line-height: 50px;
    top: 0px;
    left: 0px;
    color: #111;
    text-shadow: -1px -1px 1px rgba(255,255,255,0.1);
    text-transform: uppercase;
    transform: rotate(-90deg) translateX(-157%) translateY(73px);
    transform-origin: 0 0;
    user-select: none;
}

Последнее, но не менее важное, стили для иконок. Мы будем использовать специальный шрифт, который мы создали при помощи Fontello. Мы определим стили для тега span и псевдо-элемента :before, который будет содержать символы шрифта для иконок:

span.sb-icon {
    display: block;
    height: 70px;
    width: 70px;
    margin: 20px auto;
    user-select: none;
}
span.sb-icon:before {
    font-family: 'icons';
    font-style: normal;
    font-weight: normal;
    speak: none;
    display: block;
    text-decoration: inherit;
    text-align: center;
    text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3);
    line-height: 64px;
    width: 100%;
    font-size: 60px;
    color: #000;
    text-shadow: 0 0 1px #000;
}
.icon-cog:before { content: '\35'; } /* '5' */
.icon-flight:before { content: '\37'; } /* '7' */
.icon-eye:before { content: '\34'; } /* '4' */
.icon-install:before { content: '\39'; } /* '9' */
.icon-bag:before { content: '\36'; } /* '6' */
.icon-globe:before { content: '\38'; } /* '8' */
.icon-picture:before { content: '\32'; } /* '2' */
.icon-video:before { content: '\30'; } /* '0' */
.icon-download:before { content: '\41'; } /* 'A' */
.icon-mobile:before { content: '\42'; } /* 'B' */
.icon-camera:before { content: '\33'; } /* '3' */

И это все, что касается стилей!

JavaScript

Давайте сначала взглянем на опции нашего плагина:

$.SwatchBook.defaults = {
    center : 6,
    angleInc : 8,
    speed : 700,
    easing : 'ease',
    proximity : 45,
    neighbor : 4,
    onLoadAnim : true,
    initclosed : false,
    closeIdx : -1
};

Параметры означают следующее:

  • center: индекс центрального образца, который будет иметь угол 0 градусов при открытии меню
  • angleInc: пространство между элементами (в градусах)
  • speed & easing: скорость и функция перехода между панелями
  • proximity: расстояние от открытого образца до следующего
  • neighbor: расстояние между соседними элементами
  • onLoadAnim: если установлено значение true, меню будет открываться с анимацией при загрузке, в противном случае - оно будет сразу выводиться открытым
  • initclosed: если установлено значение true, меню будет изначально закрыто
  • closeIdx: индекс пункта, который запускает функцию открытия/закрытия меню

Мы начнем с выполнения функции _init:

_init : function( options ) {
    this.options    = $.extend( true, {}, $.SwatchBook.defaults, options );
    this.$items     = this.$el.children( 'div' );
    this.itemsCount = this.$items.length;
    this.current    = -1;
    this.support    = Modernizr.csstransitions;
    this.cache      = [];

    if ( this.options.onLoadAnim ) {
        this._setTransition();
    }

    if ( !this.options.initclosed ) {
        this._center( this.options.center, this.options.onLoadAnim );
    } else {
        this.isClosed   = true;
        if ( !this.options.onLoadAnim ) {
            this._setTransition();
        }
    }
    this._initEvents();
}

Здесь мы в основном кэшируем некоторые элементы и инициализируем некоторые переменные, которые будут использоваться в дальнейшем.

Кроме того, мы должны проверить, образец первоначально будет открыт или закрыт. Если он должен быть закрыт, нам нужно установить CSS переход для элементов (функция _setTransition).

Наконец мы загружаем события для пунктов.

_setTransition  : function() {
    if ( !this.support ) {
        return false;
    }
    this.$items.css( {
        '-webkit-transition': '-webkit-transform ' + this.options.speed + 'ms ' + this.options.easing,
        '-moz-transition'   : '-moz-transform ' + this.options.speed + 'ms ' + this.options.easing,
        '-o-transition'     : '-o-transform ' + this.options.speed + 'ms ' + this.options.easing,
        '-ms-transition'    : '-ms-transform ' + this.options.speed + 'ms ' + this.options.easing,
        'transition'        : 'transform ' + this.options.speed + 'ms ' + this.options.easing
    } );
}

Когда мы нажимаем на один из элементов, элемент будет поворачиваться до 0 градусов. Нам также необходимо повернуть соседние образцы таким образом, чтобы мы могли прочитать содержимое открытого элемента:

_initEvents : function() {
    var _self = this;
    this.$items.on( 'click.swatchbook', function( event ) {
        var $item   = $( this ),
        itmIdx  = $item.index();
        if ( itmIdx === _self.current ) {
            return false;
        }
        if ( _self.options.closeIdx !== -1 &amp;&amp; itmIdx === _self.options.closeIdx ) {
            _self._openclose();
            _self._setCurrent();
        } else {
            _self._setCurrent( $item );
            var transformStr    = 'rotate(0deg)';
            $item.css( {
                '-webkit-transform' : transformStr,
                '-moz-transform'    : transformStr,
                '-o-transform'      : transformStr,
                '-ms-transform'     : transformStr,
                'transform'         : transformStr
            } );
            _self._rotateSiblings( $item );
        }
    } );
}

Функция _rotateSiblings выглядит следующим образом:

_rotateSiblings : function( $item ) {
    var _self = this,
    idx = $item.index(),
    $cached = this.cache[ idx ], $siblings;
    if ( $cached ) {
        $siblings = $cached;
    } else {
        $siblings = $item.siblings();
        this.cache[ idx ] = $siblings;
    }
    $siblings.each( function( i ) {
        var rotateVal   = ( i < idx ) ?
        _self.options.angleInc * ( i - idx ) :
        ( i - idx === 1 ) ? _self.options.proximity : _self.options.proximity + ( i - idx - 1 ) * _self.options.neighbor;
        var transformStr    = 'rotate(' + rotateVal + 'deg)';
        $( this ).css( {
            '-webkit-transform' : transformStr,
            '-moz-transform'    : transformStr,
            '-o-transform'      : transformStr,
            '-ms-transform'     : transformStr,
            'transform'         : transformStr
        } );
    } );
}

Мы вращаем соседние образцы таким образом, чтобы оставить место для того, чтобы прочитать содержание открытого пункта. Значение определяется в настройках (proximity и neighbor).

Если мы хотим, чтобы меню с образцами было первоначально закрыто и/или мы указываем пункт, который будет запускать функцию открыть/закрыть, то событие click по этому пункту будет открывать/закрывать образец, в зависимости от его текущего состояния:

_openclose : function() {
    var _self = this;
    if ( this.isClosed ) {
        this._center( this.options.center, true );
    } else {
        this.$items.each( function( i ) {
            var transformStr = 'rotate(0deg)';
            $( this ).css( {
                '-webkit-transform' : transformStr,
                '-moz-transform'    : transformStr,
                '-o-transform'      : transformStr,
                '-ms-transform'     : transformStr,
                'transform'         : transformStr
            } );
        } );
    }
    this.isClosed = !this.isClosed;
}

И это все, я надеюсь, что вам понравилось!

Источник
Комментарии отсутствуют
Добавление комментариев доступно только зарегистрированным пользователям