Как сделать в html раскрывающийся выпадающий текст при клике на ссылку

Изображения

Слайд-шоуГалерея слайд-шоуМодальные изображенияЛайтбоксАдаптивная Сетка изображенияСетка изображенияГалерея вкладокОверлей изображенияСлайд с наложенным изображениемМасштабирование наложения изображенияНазвание наложения изображенияЗначок наложения изображенияЭффекты изображенияЧерно-белое изображениеТекст изображенияТекстовые блоки изображенийПрозрачный текст изображенияПолное изображение страницыФорма на картинкеГерой изображениеПараллельные изображенияОкругленные изображенияАватар изображенияАдаптивные образыЦентрировать изображенияМиниатюрыПознакомьтесь с командойЛипкое изображениеОтражение изображенияВстряхните изображениеПортфолио галереяПортфолио с фильтрациейМасштабирование изображенияИзображение увеличительное стеклоПолзунок сравнения изображений

Горизонтальное выпадающее меню

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

Так как мы используем абсолютное позиционирование для скрытия подпунктов, добавим правила , которые будет позиционировать подпункты относительно их родительских элементов в случае представления (используем jQuery).

.nav li {
    position: relative;
}
.nav > li.hover > ul {
    left: 0;
}
.nav li li.hover ul {
    left: 100%;
    top: 0;
}

Добавим пару строк jQuery для подключения класса .hover к элементам списка, на которые наводится курсор мыши.

$(document).ready(function() {
    $(".toggleMenu").css("display", "none");
    $(".nav li").hover(function() {
        $(this).addClass('hover');
    }, function() {
        $(this).removeClass('hover');
    });
});

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

Разметка

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

  • Код вашего меню занимает мало места
  • Меню становится доступным для поисковиков и альтернативных клиентов
  • Вы разделяете содержимое и представление, контролируя оформление только при помощи CSS

В HTML это выглядит примерно так:

Пусть вас не пугает вложенность списков. Главное — следить за правильностью открытия/закрытия тегов. В частности, каждый вложенный тег должен содержаться внутри тега .

Вот что мы пока имеем: шаг 1.

Легко изменяемые

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

  • Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.

  • Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.

  • Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.

Зачем использовать?

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

Новый подход: чудесное свойство will-change

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

Например, при применении к элементу 3D-трансформации в CSS, для этого
элемента и его содержимого может быть выделен новый слой, как мы упоминали
ранее, до того как он будет отрисован на экране. Однако, настройка элемента в
новом слое является относительно затратной операцией, которая может отложить
начало анимации трансформации на заметную долю секунды, что приводит к заметному
«подёргиванию».

Чтобы избежать задержки, можно сообщить браузеру об изменениях до того, как
они произойдут. В таком случае у него будет некоторое время чтобы
к ним приготовиться. Так что когда они произойдут, слой для
элемента будет готов, анимация может быть выполнена, элемент —
отрисован, а страница обновлена очень быстро.

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

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

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

Влияет ли на элемент как то ещё?

Ответ: и да, и нет — всё зависит от свойств, которые вы указываете. Если какое-либо
значение свойства, отличное начального, привело бы к созданию стекового
контекста для элемента, то указание этого свойства в создаст
его.

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

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

Кроме вышеперечисленного свойство никак прямым образом не влияет
на элемент, для которого применяется. Оно всего лишь является подсказкой
по отрисовке для браузера, позволяющим ему подготовиться к выполнению изменений,
которые ожидаются для этого элемента. У него нет прямого влияния на элемент кроме
создания стекового контекста и блока-обёртки в ситуациях, описанных выше.

Примеры

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

Выпадающие списки одинарных кнопок

Любую одинарную кнопку можно превратить в контролирующий элемент (кнопка открытия\скрытия) при помощи некоторых изменений разметки. Вот как вы можете это сделать также и с элементами :

Кнопка выпадающего списка

А вот так — с элементами:

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

Главная

Вторичная

Успех

Инфо

Предупреждение

Опасность

Выпадающие списки кнопок с разделенными зонами

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

Тут используется дополнительный класс, который уменьшает на 25% горизонтальный паддинг с обеих сторон выпадающей «каретки» и удаляет , добавленный для выпадающих элементов обычных кнопок. Эти изменения позволяют центрировать выпадающую «каретку» в разделенной кнопке и обеспечивают более подходящий размер зоны клика вблизи главной кнопки.

Главная

Toggle Dropdown

Вторичная

Toggle Dropdown

Успех

Toggle Dropdown

Инфо

Toggle Dropdown

Предупреждение

Toggle Dropdown

Опасность

Toggle Dropdown

Дополнительная информация

В качестве фона для подменю используется полупрозрачный PNG-файл. IE 6 не поддерживает полупрозрачность, но вы можете это исправить.

Из-за использования полупрозрачной картинки мне пришлось убрать цвет фона. Это привело к тому, что при отключенных картинках буквы подменю становятся не видны. Выход один: задать цвет фона для , потеряв при этом полупрозрачность.

Я использую хак , чтобы принудительно задать цвет меню для IE 5. Если этого не сделать, то в этом браузере фон не отображается. Наверное это можно исправить как-то по-другому, но у меня нет желания разбираться со всеми его причудами.

UPD. akella подсказал, что при некоторых настройках системы меню может распираться в Опере. Это происходит из-за использования для всех размеров «абсолютных» единиц . Пиксели — это зло.
Поэтому я сделал второй вариант полностью на (кроме ширины границы). И именно из-за этой однопиксельной рамки могут появляться небольшие зазоры при увеличении размера шрифта. Выход — не используйте границу =)

Медиа-список

Пример ниже показывает возможность использования медиа компонента в качестве списка (например для комментариев или связанных статей).

  • Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis.

    Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis.

    Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis.

    Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis.

  • Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis.

Вертикальное выпадающее меню

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

<meta name="viewport" content="width=device-width, initial-scale=1">

Конечно, даже тепрь меню выглядит ужасно, хотя и помещается на экране. Нужно использовать медиа запрос для установки соответствующих стилей, чтобы выводить наш список вертикально после того, как размер экрана достигнет точки разрыва. Точка разрыва определяется значением ширины экрана, когда меню начинает выстраиваться в две строки, для нашего примера — 800px.

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

@media screen and (max-width: 800px) {
    .nav > li {
        float: none;
    }
    .nav ul {
        display: block;
        width: 100%;
    }
   .nav > li.hover > ul , .nav li li.hover ul {
        position: static;
    }
}

Мы же не зря назвали это меню «выпадающим»

Мы дописываем к уже существующему правилу:

следующие инструкции:

Выражение служит для абсолютного позиционирования подменю относительно элемента верхнего уровня.

Когда мы имеем родительский элемент, позиционированный «относительно» (т. е. имеющий ), все позиционированные абсолютно элементы, содержащиеся в нем, будут позиционироваться относительно родительского элемента, а не относительно всей страницы.

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

Ширина нашего подменю равна 138 пикселям из-за того, что мы вычитаем 2 пикселя от границ с каждой стороны: 140 – 1 – 1 = 138 пикселей.

Селектор оказывает влияние на подменю 3-го уровня. Мы его сдвигаем влево на ширину 133 пикселя (величина чисто эмпирическая), а также немного вверх (чтобы оно оказалось на одном уровне с активной ссылкой). Теперь, при наведении мышки, наше подменю будет выскакивать справа от ссылки.

Выпадающее меню (пока не для IE): шаг 4.

Старый подход: приём translateZ() (или translate3d())

Уже довольно давно, чтобы обмануть браузер и заставить его применить
аппаратное ускорение для операций анимации и трансформаций, используется так
называемый приём (или ). Это происходит путём
добавления простой 3D-трансформации для элемента, который не будет
трансформироваться в трёхмерном пространстве. Например, чтобы получить
аппаратное ускорение для двухмерной анимации элемента, нужно добавить это
простое правило:

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

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

Выравнивание меню

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

Внимание! Выпадающие списки позиционируются благодаря Popper.js (за исключением случаев, когда они содержатся в navbar). Right-aligned menu

Action
Another action
Something else here

Right-aligned menu

Action
Another action
Something else here

Отзывчивое выравнивание

Если вы хотите использовать адаптивное выравнивание, отключите динамическое позиционирование, добавив атрибут , и используйте классы адаптивных вариантов.

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

Left-aligned but right aligned when large screen

Action
Another action
Something else here

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

Right-aligned but left aligned when large screen

Action
Another action
Something else here

Обратите внимание, что вам не нужно добавлять атрибут к выпадающим кнопкам на панелях навигации, поскольку Popper.js не используется на панелях навигации

Навигационный список Он же Сайдбар

Навигационный список позволяет создать легкую и удобную в использовании навигацию с дополнительными заголовками. Такой сайдбар используется в Finder в MAC OS X.

Пример навигационного списка

К списку ссылок и добавьте классы — :

  • Заголовок
  • Второй заголовок
  • Заголовок
  • Еще заголовок
<ul class="nav nav-list">
  <li class="nav-header">Заголовок</li>
  <li class="active"><a href="#">На главную</a></li>
  <li><a href="#">Библиотека</a></li>
  ...
</ul>

Замечание
Для вложения в навигационные списки, применяйте классы только к вложенным элементам — .

Горизонтальный разделитель

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

<ul class="nav nav-list">
  ...
  <li class="divider"></li>
  ...
</ul>

Фиксация элемента на сайте при прокрутке страницы с остановкой в нужном месте на jQuery

Этот вариант является доработкой вышеуказанного способа. Я много видел сайтов, где в сайдбаре (боковой колонке сайта) фиксируются различные рекламные блоки

Все бы ничего, но при прокрутке страницы до самого низа такие блоки перекрывают футер (низ сайта) и зачастую препятствуют получению немаловажной информации или навигации в нем

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

Реализация:

Ну и те же стили из второго варианта с небольшим дополнением:

На что здесь стоить обратить внимание?

«.fixed_block» – это элемент, который мы фиксируем при прокрутке. «.fixed_block_position» — класс обертки, а «.fixed_block_stop» – это элемент (граница), достигнув которую элемент остановит свое движение (фиксацию).

Боремся с проблемами браузеров

К сожалению, не во всех браузерах применяются нужные стили, когда переключаешься между и . Для того, чтобы вызвать перерисовку, мы должны перезаписать текстовое содержимое тега . Самый простой способ, который я нашёл, — это использовать метод . Любопытно, что он нужен только для Chrome.

{this.isActive() ? this.css.trim() : this.css}

Сохраняем настройки темы

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

this.store = typeof localStorage === 'undefined' ? null : localStorage;

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

componentDidMount() {  if (this.store) {    this.setState({      active: this.store.getItem('ThemeSwitch') || false    });     } }

Так как управление состоянием в React происходит асинхронно, недостаточно просто сохранять изменённое состояние после того, как оно было дополнено. Вместо этого мне нужно использовать метод :

componentDidUpdate() {    if (this.store) {    this.store.setItem('ThemeSwitch', this.state.active);  }}

Скрываем в неподдерживаемых браузерах

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

Если вы когда-нибудь имели дело с Modernizr, то могли бы использовать похожий тест свойства и его значения для CSS. Однако не стоит его здесь использовать, поскольку мы не хотим, чтобы наш компонент имел какие-либо зависимости, если в этом нет необходимости.

invertSupported (property, value) {    var prop = property + ':',      el = document.createElement('test'),      mStyle = el.style;  el.style.cssText = prop + value;  return mStyle;}componentDidMount() {    if (this.store) {    this.setState({      supported: this.invertSupported('filter', 'invert(100%)'),      active: this.store.getItem('ThemeSwitch') || false    });  }}

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

<div hidden={!this.state.supported}>    <!-- контент компонента --></div>

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

 {  display: none;}

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

Значение по умолчанию

Чтобы сделать компонент более надёжным и дать Implementor возможность пропустить атрибут, мы также можем добавить . После определения класса компонента можно использовать следующее:

ThemeSwitch.defaultProps = { preserveRasters: true }

Устанавливаем компонент

Пример такого компонента есть в NPM:

npm i --save react-theme-switch

Помимо этого, простой пример с JavaScript, в основе которого лежит чекбокс, есть на СodePen:

Расположение

Осталось только решить, где мы собираемся разместить компонент в документе. Как правило, утилиты вроде выбора темы следует искать в области ориентиров (landmark region), а не в , поскольку пользователь скринридера ожидает, что этот контент будет меняться между страницами. Допустимы () или ().

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

Примите во внимание , который здесь применяется

Чеклист

  • Внедряйте полезные функции только в том случае, если снижение производительности минимально, а конечный интерфейс не становится сильно сложнее.
  • Используйте в интерфейсах только поддерживаемые функции. Используйте поддержку фич (feature detection).
  • Используйте семантическую разметку в React-компоненте: такие компоненты всегда будут работать!
  • Используйте пропсы для того, чтобы сделать ваши компоненты более конфигурируемыми и иметь возможность использовать их много раз.

Изначальные установки Одинаковая разметка, разные классы

Все навигационные компоненты—вкладки, кнопки и списки—имеют одинаковую HTML-разметку и родительский класс .

Вкладки

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

<ul class="nav nav-tabs">
  <li class="active">
    <a href="#">Главная</a>
  </li>
  <li><a href="#">...</a></li>
  <li><a href="#">...</a></li>
</ul>

Навигационные кнопки

Используйте HTML-код из предыдущего примера, но вместо класса используйте :

<ul class="nav nav-pills">
  <li class="active">
    <a href="#">Home</a>
  </li>
  <li><a href="#">...</a></li>
  <li><a href="#">...</a></li>
</ul>

Отключенное состояние

Для любого элемента навигации (вкладки, кнопки или списки), добавьте класс для изменения стилей — серый шрифт и отсутвие анимации при наведении курсора. Тем не менее ссылки и элементы останутся кликабельными, до тех пор пока Вы не уберете атрибут . Либо управляя элементами через JavaScript.

<ul class="nav nav-pills">
  ...
  <li class="disabled"><a href="#">Главная</a></li>
  ...
</ul>

Кнопка + Кнопка-список

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

Кнопка

Кнопка

Внимание

Оранжевая

Зеленая

Инфо

Обратная

<div class="btn-group">
  <button class="btn">Кнопка</button>
  <button class="btn dropdown-toggle" data-toggle="dropdown">
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu">
    <!-- dropdown menu links -->
  </ul>
</div>

Размеры

Используйте классы размеров кнопок , или .

Большая кнопка

Маленькая кнопка

Mini-кнопка

<div class="btn-group">
  <button class="btn btn-mini">Кнопка</button>
  <button class="btn btn-mini dropdown-toggle" data-toggle="dropdown">
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu">
    <!-- dropdown menu links -->
  </ul>
</div>

Выпадающие вверх

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

Выпадающий вверх

Выпадающий вверх и вправо

Доступность

Стандарт
WAI ARIA описывает и определяет виджет как настоящий виджет, но лишь для меню приложений, запускающих действия или функции. Меню ARIA могут содержать лишь пункты меню, чекбоксы, радио-кнопки, группы радио-кнопок и подменю.

Выпадающие списки Bootstrap, с другой стороны, спроектированы для решения множества задач и могут работать в разных структурах разметки. Например, можно создать выпадающие списки, содержащие дополнительные поля ввода и элементы контроля форм, такие как поиск или поле ввода логина. По этой причине Bootstrap не ожидает (и не добавляет автоматически) ни один из атрибутов ( и ), необходимых для меню согласно стандарту ARIA.

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

Заключение

Свойство — это инструмент, который поможет нам писать
оптимизированный и сверхбыстрый код без применения хаков, и наделять
производительность определенных CSS-операции большей значимостью.
Однако, как всегда, с большей силой приходит бо́льшая ответственность,
является одним из тех свойств, которые не следует
воспринимать легкомысленно, но нужно использовать с умом. В этом месте
я процитирую Таба Аткинса (Tab Atkins Jr.), редактора спецификации :

Спасибо, что прочитали эту статью!

Огромное спасибо Полу Льюису (Paul Lewis), что просмотрел эту статью и поделился своими
впечатлениями, Табу Аткинсу за поддержку и ответы, а также Брюсу Лоусону (Bruce Lawson) и
Матиасу Байненсу (Mathias Bynens) за рецензирование статьи.

Рейтинг
( Пока оценок нет )
Editor
Editor/ автор статьи

Давно интересуюсь темой. Мне нравится писать о том, в чём разбираюсь.

Понравилась статья? Поделиться с друзьями:
Люкс-хост
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: