Яндекс.Метрика

Дизайн-журнал №1. Актуальная информация для дизайнеров, веб дизайнеров, программистов и разработчиков сайтов.

Создание выпадающих списков

20 марта 2013 | Опубликовано в css | 3 Комментариев »

Целью сегодняшнего урока будет показать, как создавать раскрывающиеся списки с помощью CSS и jQuery. Это будет пять списков, которые вы можете использовать для различных идей. В фрагментах кода вы не найдете никаких вендерных префиксов, но их сможете найти в исходных файлах.  

 

 

 

  • Демо                            Скачать исходные фалы 

    Также в уроке будем использовать box-model, где   [width]= [element-width]+ [padding]+ [borders]. Давайте активируем с помощью следующего сниппета:
    *,
    *:after,
    *:before {
        box-sizing: border-box;
    }


С чего будем начинать?

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

 
<div class="wrapper-dropdown">
    <span>I'm kinda the label!</span>
    <ul class="dropdown">
        <li>I'm hidden!</li>
        <li>Me too!</li>
        <li>So do I.</li>
    </ul>
</div>

JAVASCRIPT

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

//...

obj.dd.on('click', function(event){
    $(this).toggleClass('active');
    return false;
});

//...

$(function() {

    var dd = new DropDown( $('#dd') );

    $(document).click(function() {
        // all dropdowns
        $('.wrapper-dropdown-1').removeClass('active');
    });
});

 

Что же именно делает этот скрипт? Во-первых, он переключает класс .active, при нажатии на элементе. Это означает, если оболочка не имеет этот  класс, он добавляет его и потом, если активным является другое меня — соответственно удаляет его. Во -вторых, он позволяет закрывать список при нажатии на любом другом месте на экране.

Теперь мы понимаем, как это работает, и  пришло время для создания некоторых раскрывающихся списков!

Пример 1

Давайте начнем с чего-нибудь простого.

Разметка

Нам нужно несколько вещей: класс wrapper, (скрытый) выпадающий список, и название, которое поместим в тег span. Также будем использовать якоря. 

 

<div id="dd" class="wrapper-dropdown-1" tabindex="1">
    <span>Gender</span>
    <ul class="dropdown">
        <li><a href="#">Male</a></li>
        <li><a href="#">Female</a></li>
    </ul>
</div>

CSS

Давайте посмотрим на стили, на которые мы будем фокусировать наше внимание.  Начнем с  wrapper:

 

.wrapper-dropdown {
    /* Size and position */
    position: relative; /* Enable absolute positioning for children and pseudo elements */
    width: 200px;
    padding: 10px;
    margin: 0 auto;

    /* Styles */
    background: #9bc7de;
    color: #fff;
    outline: none;
    cursor: pointer;
    /* Font settings */
    font-weight: bold;
}

Сначала мы установили ширину нашей выпадающего меню и некоторые paddings и margins. Далее, мы задали ему некоторые стили. И, наконец, мы устанавливаем некоторые параметры для шрифта. Дальше зададим стили для названия. 

.wrapper-dropdown:after{

    content: "";
    width: 0;
    height: 0;
    position: absolute;
    right: 16px;
    top: 50%;
    margin-top: -6px;
    border-width: 6px 0 6px 6px;
    border-style: solid;
    border-color: transparent #fff;
}

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

.wrapper-dropdown-1.dropdown{
    /* Size & position */
    position: absolute;
    top: 100%;
    left: 0; /* Size */
    right: 0; /* Size */

    /* Styles */
    background: #fff;
    font-weight: normal; /* Overwrites previous font-weight: bold; */
    /* Hiding */
    opacity: 0;
    pointer-events: none;
}

Что мы только что сделали? Мы задали для списка абсолютную позицию и поставили его позади кнопки  (top: 100%;). Мы задали для него такую же ширину, как и для кнопки с значениями  left и right — о. И что еще является очень важным — скрыли его, уменьшив прозрачность до 0. Свойство pointer-events:none, но это не означает, что его нет. 

Приведем несколько стилей для списка элементов:

.wrapper-dropdown-1 .dropdown li a {
    display: block;
    text-decoration: none;
    color: #9e9e9e;
    padding: 10px 20px;
}
/* Hover state */
.wrapper-dropdown-1 .dropdown li:hover a {
    background: #f3f8f8;
}

Итак, у нас есть кнопка и скрытые элементы раскрывающегося меню. Теперь мы посмотри на открытое меню, которое выпадает при нажатии на кнопку. 

С помощью JavaScript мы переключаем класс .active при нажатии на кнопку, чтобы с помощью этого класса мы смогли изменить наш CSS.

 

/* Active state */
.wrapper-dropdown-1.active .dropdown {
    opacity: 1;
    pointer-events: auto;
}

.wrapper-dropdown-1.active:after {
    border-color: #9bc7de transparent;
    border-width: 6px 6px 0 6px ;
    margin-top: -3px;
}
.wrapper-dropdown-1.active {
  background: #9bc7de;
  background: linear-gradient(to right, #9bc7de 0%, #9bc7de 78%, #ffffff 78%, #ffffff 100%);
}

Здесь происходит три вещи:

  • Для начала мы показываем выпадающий список, установив opacity на 1. Не забудьте для pointer-event установит значение  auto. 
  • Дальше мы меняем направление и цвет маленькой стрелки.
  • Затем изменяем фон, использую градиент. 

JavaScript

Последнее, но не менее важное, мы также должны добавить еще один фрагмент JavaScript, чтобы при нажатии отображалось выбранное событие. 

function DropDown(el) {
    this.dd = el;
    this.placeholder = this.dd.children('span');
    this.opts = this.dd.find('ul.dropdown > li');
    this.val = '';
    this.index = -1;
    this.initEvents();
}
DropDown.prototype = {
    initEvents : function() {
        var obj = this;

        obj.dd.on('click', function(event){
            $(this).toggleClass('active');
            return false;
        });
        obj.opts.on('click',function(){
            var opt = $(this);
            obj.val = opt.text();
            obj.index = opt.index();
            obj.placeholder.text('Gender: ' + obj.val);
        });
    },
    getValue : function() {
        return this.val;
    },
    getIndex : function() {
        return this.index;
    }
}

 

Пример 2

Разметка

<div id="dd" class="wrapper-dropdown-2">Sign in with
    <ul class="dropdown">
        <li><a href="#"><i class="icon-twitter icon-large"></i>Twitter</a></li>
        <li><a href="#"><i class="icon-github icon-large"></i>Github</a></li>
        <li><a href="#"><i class="icon-facebook icon-large"></i>Facebook</a></li>
    </ul>
</div>

 

<i> используется, чтобы отобразить иконки с FontAwesome

CSS

Как и в следующем примере начнем со стилей. Обратите внимание на  left border -  5px.

 

.wrapper-dropdown-2 {
    /* Size and position */
    position: relative; /* Enable absolute positioning for children and pseudo elements */
    width: 200px;
    margin: 0 auto;
    padding: 10px 15px;
    /* Styles */
    background: #fff;
    border-left: 5px solid grey;
    cursor: pointer;
    outline: none;
}

Теперь маленькая стрелка. Точно так же, как раньше:

.wrapper-dropdown-2:after {
    content: "";
    width: 0;
    height: 0;
    position: absolute;
    right: 16px;
    top: 50%;
    margin-top: -3px;
    border-width: 6px 6px 0 6px;
    border-style: solid;
    border-color: grey transparent;
}

Переходим к раскрывающему списку. 

.wrapper-dropdown-2 .dropdown {
  /* Size & position */
    position: absolute;
    top: 100%;
    left: -5px;
    right: 0px;

    /* Styles */
    background: white;
    transition: all 0.3s ease-out;
    list-style: none;
    /* Hiding */
    opacity: 0;
    pointer-events: none;
}

Обратите внимание, что на transition, который мы будем использовать, чтобы сделать постепенно раскрывающийся список, а не просто всплывающий, как в первом пример.  

.wrapper-dropdown-2 .dropdown li a {
    display: block;
    text-decoration: none;
    color: #333;
    border-left: 5px solid;
    padding: 10px;
    transition: all 0.3s ease-out;
}

.wrapper-dropdown-2 .dropdown li:nth-child(1) a {
    border-left-color: #00ACED;
}

.wrapper-dropdown-2 .dropdown li:nth-child(2) a {
    border-left-color: #4183C4;
}

.wrapper-dropdown-2 .dropdown li:nth-child(3) a {
    border-left-color: #3B5998;
}

.wrapper-dropdown-2 .dropdown li i {
    margin-right: 5px;
    color: inherit;
    vertical-align: middle;
}

/* Hover state */
.wrapper-dropdown-2 .dropdown li:hover a {
    color: grey;
}

В отрытом состоянии стрелка изменяет свою позицию, а раскрывающийся список становится видимым. 

.wrapper-dropdown-2.active:after {
    border-width: 0 6px 6px 6px;
}
.wrapper-dropdown-2.active .dropdown {
    opacity: 1;
    pointer-events: auto;
}

JavaScript

function DropDown(el) {
    this.dd = el;
    this.initEvents();
}
DropDown.prototype = {
    initEvents : function() {
        var obj = this;
        obj.dd.on('click', function(event){
            $(this).toggleClass('active');
            event.stopPropagation();
        });
    }
}

Пример 3

This one is probably the one which comes the closest to a regular select element. Indeed, when you pick something, the label’s default value is replaced by the picked value. On a side note: it looks great doesn’t it?

Разметка

<div id="dd" class="wrapper-dropdown-3" tabindex="1">
    <span>Transport</span>
    <ul class="dropdown">
        <li><a href="#"><i class="icon-envelope icon-large"></i>Classic mail</a></li>
        <li><a href="#"><i class="icon-truck icon-large"></i>UPS Delivery</a></li>
        <li><a href="#"><i class="icon-plane icon-large"></i>Private jet</a></li>
    </ul>
</div>

 

CSS

.wrapper-dropdown-3 {
    /* Size and position */
    position: relative;
    width: 200px;
    margin: 0 auto;
    padding: 10px;

    /* Styles */
    background: #fff;
    border-radius: 7px;
    border: 1px solid rgba(0,0,0,0.15);
    box-shadow: 0 1px 1px rgba(50,50,50,0.1);
    cursor: pointer;
    outline: none;
    /* Font settings */
    font-weight: bold;
    color: #8AA8BD;
}
Здесь мы используем border, тени и закругленные углы. 
.wrapper-dropdown-3:after {
    content: "";
    width: 0;
    height: 0;
    position: absolute;
    right: 15px;
    top: 50%;
    margin-top: -3px;
    border-width: 6px 6px 0 6px;
    border-style: solid;
    border-color: #8aa8bd transparent;
}

Перейдем к выпадающему меню:

.wrapper-dropdown-3 .dropdown {
  /* Size & position */
    position: absolute;
    top: 140%;
    left: 0;
    right: 0;

    /* Styles */
    background: white;
    border-radius: inherit;
    border: 1px solid rgba(0,0,0,0.17);
    box-shadow: 0 0 5px rgba(0,0,0,0.1);
    font-weight: normal;
    transition: all 0.5s ease-in;
    list-style: none;

    /* Hiding */
    opacity: 0;
    pointer-events: none;
}

.wrapper-dropdown-3 .dropdown li a {
    display: block;
    padding: 10px;
    text-decoration: none;
    color: #8aa8bd;
    border-bottom: 1px solid #e6e8ea;
    box-shadow: inset 0 1px 0 rgba(255,255,255,1);
    transition: all 0.3s ease-out;
}

.wrapper-dropdown-3 .dropdown li i {
    float: right;
    color: inherit;
}

.wrapper-dropdown-3 .dropdown li:first-of-type a {
    border-radius: 7px 7px 0 0;
}

.wrapper-dropdown-3 .dropdown li:last-of-type a {
    border-radius: 0 0 7px 7px;
    border: none;
}

/* Hover state */
.wrapper-dropdown-3 .dropdown li:hover a {
    background: #f3f8f8;
}

.wrapper-dropdown-3.dropdown:after{

    content: "";
    width: 0;
    height: 0;
    position: absolute;
    bottom: 100%;
    right: 15px;
    border-width: 0 6px 6px 6px;
    border-style: solid;
    border-color: #fff transparent;
}
.wrapper-dropdown-3 .dropdown:before {
    content: "";
    width: 0;
    height: 0;
    position: absolute;
    bottom: 100%;
    right: 13px;
    border-width: 0 8px 8px 8px;
    border-style: solid;
    border-color: rgba(0,0,0,0.1) transparent;
}

Мы создали белый треугольник на верхней части списка.

В отрытом виде.  Обратите внимание, как мы установили переход к</code><code>.dropdown.Немного больше, чем обычно  (0.5s вместо 0.3s).  Таким образом,  меню открывается  очень гладко.

.wrapper-dropdown-3.active .dropdown {
    opacity: 1;
    pointer-events: auto;
}

JavaScript

 

function DropDown(el) {
    this.dd = el;
    this.placeholder = this.dd.children('span');
    this.opts = this.dd.find('ul.dropdown > li');
    this.val = '';
    this.index = -1;
    this.initEvents();
}
DropDown.prototype = {
    initEvents : function() {
        var obj = this;

        obj.dd.on('click', function(event){
            $(this).toggleClass('active');
            return false;
        });
        obj.opts.on('click',function(){
            var opt = $(this);
            obj.val = opt.text();
            obj.index = opt.index();
            obj.placeholder.text(obj.val);
        });
    },
    getValue : function() {
        return this.val;
    },
    getIndex : function() {
        return this.index;
    }
}

Пример 4

Создаем список с другим типом. Ничего особенного, но отличается от предыдущих демо.

Разметка

<div id="dd" class="wrapper-dropdown-4">To do
    <ul class="dropdown">
        <li><input type="checkbox" id="el-1" name="el-1" value="donut"><label for="el-1">Eat a donut</label></li>
        <li><input type="checkbox" id="el-2" name="el-2" value="neighbour"><label for="el-2">Spy on my neighbours</label></li>
        <li><input type="checkbox" id="el-3" name="el-3" value="T-rex"><label for="el-3">Feed my T-Rex</label></li>
    </ul>
</div>

Теперь без ссылок и иконок. У наст просто есть checkbox. 

 

CSS

.wrapper-dropdown-4 {
    /* Size and position */
    position: relative;
    width: 270px;
    margin: 0 auto;
    padding: 10px 10px 10px 30px;
    /* Styles */
    background: #fff;
    border: 1px solid silver;
    cursor: pointer;
    outline: none;
}

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

.wrapper-dropdown-4:after {
    content: "";
    width: 0;
    height: 0;
    position: absolute;
    right: 10px;
    top: 50%;
    margin-top: -3px;
    border-width: 6px 6px 0 6px;
    border-style: solid;
    border-color: #ffaa9f transparent;
}

Выпадающее меню:

.wrapper-dropdown-4 .dropdown {
    /* Size & position */
    position: absolute;
    top: 100%;
    margin-top: 1px; /* border of wrapper */
    left: -1px;
    right: -1px;

    /* Styles */
    background: white;
    border: 1px solid silver;
    border-top: none;
    list-style: none;
    transition: all 0.3s ease-out;
    /* Hiding */
    opacity: 0;
    pointer-events: none;
}

Мы должны установитьmargin-top в 1px.

.wrapper-dropdown-4 .dropdown li {
    position: relative; /* Enable absolute positioning for checkboxes */
}

.wrapper-dropdown-4 .dropdown li label {
    display: block;
    padding: 10px 10px 10px 30px; /* Same padding as the button */
    border-bottom: 1px dotted #1ccfcf;
    transition: all 0.3s ease-out;
}

.wrapper-dropdown-4 .dropdown li:last-of-type label {
    border: none;
}

.wrapper-dropdown-4 .dropdown li input /* Checkboxes */ {
    position: absolute;
    display: block;
    right: 10px;
    top: 50%;
    margin-top: -8px;
}

/* Hover state */

.wrapper-dropdown-4 .dropdown li:hover label {
    background: #f0f0f0;
}

/* Checked state */
.wrapper-dropdown-4 .dropdown li input:checked ~ label {
    color: grey;
    text-decoration: line-through;
}

При нажатии на флажок соответствующая этикетка становится серой и перечеркнутой. Просто, но эффективная.

И теперь мы имеем дело с двумя тонкими красными линиями слева от нашей записи. Есть два способа сделать это: с псевдо-элементами и с градиентами. Давайте посмотрим на них:

/* Red lines: the pseudo-elements way */
.wrapper-dropdown-4 .dropdown:before,
.wrapper-dropdown-4:before {
    content: "";
    width: 4px;
    height: 100%;
    position: absolute;
    top: 0;
    left: 15px;
    border: 1px solid #ffaa9f;
    border-top: none;
    border-bottom: none;
    z-index: 2;
}

/* OR: */
/* Red lines: the gradients way */

.wrapper-dropdown-4 .dropdown,
.wrapper-dropdown-4 {
  background: linear-gradient(left, white 5%, #ffaa9f 5%, #ffaa9f 5.3%, white 5.3%, white 6.5%, #ffaa9f 6.5%, #ffaa9f 6.8%, white 6.8%);
}
.wrapper-dropdown-4 .dropdown li:hover label {
  background: linear-gradient(left, #f0F0F0 5%, #ffaa9f 5%, #ffaa9f 5.3%, #f0F0F0 5.3%, #f0F0F0 6.5%, #ffaa9f 6.5%, #ffaa9f 6.8%, #f0F0F0 6.8%);
}

 

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

 

/* Active state */

.wrapper-dropdown-4.active:after {
    border-width: 0 6px 6px 6px;
}
.wrapper-dropdown-4.active .dropdown {
    opacity: 1;
    pointer-events: auto;
}

JavaScript

function DropDown(el) {
    this.dd = el;
    this.opts = this.dd.find('ul.dropdown > li');
    this.val = [];
    this.index = [];
    this.initEvents();
}
DropDown.prototype = {
    initEvents : function() {
        var obj = this;

        obj.dd.on('click', function(event){
            $(this).toggleClass('active');
            event.stopPropagation();
        });

        obj.opts.children('label').on('click',function(event){
            var opt = $(this).parent(),
                chbox = opt.children('input'),
                val = chbox.val(),
                idx = opt.index();
            ($.inArray(val, obj.val) !== -1) ? obj.val.splice( $.inArray(val, obj.val), 1 ) : obj.val.push( val );
            ($.inArray(idx, obj.index) !== -1) ? obj.index.splice( $.inArray(idx, obj.index), 1 ) : obj.index.push( idx );
        });
    },
    getValue : function() {
        return this.val;
    },
    getIndex : function() {
        return this.index;
    }
}

Пример 5

Наш последний пример.  

Разметка

<div id="dd" class="wrapper-dropdown-5" tabindex="1">John Doe
    <ul class="dropdown">
        <li><a href="#"><i class="icon-user"></i>Profile</a></li>
        <li><a href="#"><i class="icon-cog"></i>Settings</a></li>
        <li><a href="#"><i class="icon-remove"></i>Log out</a></li>
    </ul>
</div>

The CSS

.wrapper-dropdown-5 {
    /* Size & position */
    position: relative;
    width: 200px;
    margin: 0 auto;
    padding: 12px 15px;

    /* Styles */
    background: #fff;
    border-radius: 5px;
    box-shadow: 0 1px 0 rgba(0,0,0,0.2);
    cursor: pointer;
    outline: none;
    transition: all 0.3s ease-out;
}
.wrapper-dropdown-5:after { /* Little arrow */
    content: "";
    width: 0;
    height: 0;
    position: absolute;
    top: 50%;
    right: 15px;
    margin-top: -3px;
    border-width: 6px 6px 0 6px;
    border-style: solid;
    border-color: #4cbeff transparent;
}

Раскрывающийся список немного отличается от обычного.

.wrapper-dropdown-5 .dropdown {
    /* Size & position */
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;

    /* Styles */
    background: #fff;
    border-radius: 0 0 5px 5px;
    border: 1px solid rgba(0,0,0,0.2);
    border-top: none;
    border-bottom: none;
    list-style: none;
    transition: all 0.3s ease-out;
    /* Hiding */
    max-height: 0;
    overflow: hidden;
}

Простые стили для элементов списка.

.wrapper-dropdown-5 .dropdown li {
    padding: 0 10px ;
}

.wrapper-dropdown-5 .dropdown li a {
    display: block;
    text-decoration: none;
    color: #333;
    padding: 10px 0;
    transition: all 0.3s ease-out;
    border-bottom: 1px solid #e6e8ea;
}

.wrapper-dropdown-5 .dropdown li:last-of-type a {
    border: none;
}

.wrapper-dropdown-5 .dropdown li i {
    margin-right: 5px;
    color: inherit;
    vertical-align: middle;
}

/* Hover state */
.wrapper-dropdown-5 .dropdown li:hover a {
    color: #57a9d9;
}

В активном состоянии:

/* Active state */

.wrapper-dropdown-5.active {
    border-radius: 5px 5px 0 0;
    background: #4cbeff;
    box-shadow: none;
    border-bottom: none;
    color: white;
}

.wrapper-dropdown-5.active:after {
    border-color: #82d1ff transparent;
}
.wrapper-dropdown-5.active .dropdown {
    border-bottom: 1px solid rgba(0,0,0,0.2);
    max-height: 400px;
}

Когда выпадающий список открыт, мы меняем нижние углы кнопки, цвет, направление и цвет стрелки. 

И, чтобы открыть меню, мы устанавливаем макс-высота выпадающий на 400px. Мы могли бы установить его на 500px, 1000px — это не имеет значение.

The JavaScript

function DropDown(el) {
    this.dd = el;
    this.initEvents();
}
DropDown.prototype = {
    initEvents : function() {
        var obj = this;
        obj.dd.on('click', function(event){
            $(this).toggleClass('active');
            event.stopPropagation();
        });
    }
}

Откаты

У нас есть 5 выпадающих меню. Но как насчет старых браузеров?

В игру вступает наш друг  Modernizr. Для тех, кто не знает, что такое Modernizr  - это библиотека JavaScript, которая обнаруживает HTML5 и CSS3-функции в браузере пользователя. 

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

/* No CSS3 support */

.no-opacity       .wrapper-dropdown-1 .dropdown,
.no-pointerevents .wrapper-dropdown-1 .dropdown {
    display: none;
    opacity: 1; /* If opacity support but no pointer-events support */
    pointer-events: auto; /* If pointer-events support but no pointer-events support */
}
.no-opacity       .wrapper-dropdown-1.active .dropdown,
.no-pointerevents .wrapper-dropdown-1.active .dropdown {
    display: block;
}

 

Если браузер не поддерживает непрозрачность или указатель событий, мы скрываем выпадающее меню простым display: none.

Если браузер не поддерживает прозрачность, но поддерживает указатель событий, мы устанавливаем pointer-events: auto.

 

Если браузер не поддерживает указатель событий, но поддерживающий прозрачность, мы поставили opacity: 1. 

 

Автор урока: HUGO GIRAUDEL

Перевод — Дежурка




Комментарии

  1. Cris
    Thumb up Thumb down 0

    Большое спасибо за урок. Планирую применить данные выпадающие списки на своем сайте www.cs-market.com вместо my account блока.

  2. Александр
    Thumb up Thumb down +1

    :-!

    Отвратительная непроверенная статья!!!

    В примерах: 5 и еще нескольких вообще не выберается значение при клике, помимо этого необходимо оговаривать, что подключены сторонние библиотеки в верстке... И думаю еще, что-то но не захотелось продолжать

  3. Евгений
    Thumb up Thumb down 0

    Здравствуйте! Подскажите пожалуйста пример выпадающего списка, где при клике пункта под списком меняется контент?