renovations
This commit is contained in:
parent
718ab327f9
commit
e706693c7e
12 changed files with 246 additions and 257 deletions
|
@ -22,12 +22,14 @@
|
|||
|
||||
```html
|
||||
<ul class="menu">
|
||||
<li class="item"><a href="#">Главная</a></li>
|
||||
<li class="vertical-splitter"></li>
|
||||
<li class="item"><a href="#">Товары</a></li>
|
||||
<li class="item"><a href="#">Фотографии</a></li>
|
||||
<li class="item"><a href="#">Контакты</a></li>
|
||||
<li class="menu__item"><a href="#">Главная</a></li>
|
||||
<li class="menu__vertical-splitter"></li>
|
||||
<li class="menu__item"><a href="#">Товары</a></li>
|
||||
<li class="menu__item"><a href="#">Фотографии</a></li>
|
||||
<li class="menu__item"><a href="#">Контакты</a></li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
[edit src="solution"]Полное меню со стилями[/edit]
|
||||
Дополнительно, классы помечены префиксом компонента, на тот случай, если в заголовках появится произвольный HTML.
|
||||
|
||||
|
||||
|
|
|
@ -8,15 +8,13 @@
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
.menu li {
|
||||
.menu__item {
|
||||
list-style: none;
|
||||
|
||||
float: left;
|
||||
display: inline-block;
|
||||
padding: 6px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.menu li.item {
|
||||
border: 1px solid gray;
|
||||
border-radius: 10px;
|
||||
|
||||
|
@ -25,16 +23,21 @@
|
|||
background: #FFF5EE;
|
||||
}
|
||||
|
||||
.menu li.vertical-splitter:before {
|
||||
.menu__vertical-splitter {
|
||||
list-style: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.menu__vertical-splitter:before {
|
||||
content: "|";
|
||||
}
|
||||
|
||||
.menu .item a {
|
||||
.menu__item a {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.menu .item a:hover {
|
||||
.menu__item a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
@ -43,11 +46,11 @@
|
|||
<body>
|
||||
|
||||
<ul class="menu">
|
||||
<li class="item"><a href="#">Главная</a></li>
|
||||
<li class="vertical-splitter"></li>
|
||||
<li class="item"><a href="#">Товары</a></li>
|
||||
<li class="item"><a href="#">Фотографии</a></li>
|
||||
<li class="item"><a href="#">Контакты</a></li>
|
||||
<li class="menu__item"><a href="#">Главная</a></li>
|
||||
<li class="menu__vertical-splitter"></li>
|
||||
<li class="menu__item"><a href="#">Товары</a></li>
|
||||
<li class="menu__item"><a href="#">Фотографии</a></li>
|
||||
<li class="menu__item"><a href="#">Контакты</a></li>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -44,6 +44,6 @@
|
|||
|
||||
[iframe src="source" border=1 height=50 edit link]
|
||||
|
||||
Что делает эту вёрстку несемантичной? Найдите 3 ошибки.
|
||||
Что делает эту вёрстку несемантичной? Найдите 3 ошибки (или больше).
|
||||
|
||||
Как бы вы сверстали меню правильно?
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
<ul>
|
||||
<li>Самая главная ошибка: классы без префиксов. Это означает, что если внутри содержимого будет что-либо с классом `.headers`, то стили оформят это как заголовок таба. Что, конечно же, будет неверно.</li>
|
||||
<li>Класс `selected`, соответствующий "текущей" выбранной вкладке, находится на ссылке:
|
||||
|
||||
```html
|
||||
<li><a href="#tabs-3" class="selected">Открытая вкладка</a></li>
|
||||
```
|
||||
|
||||
...Но состояние "выбранности" относится к заголовку `LI` целиком. Для его нормального отображения класс должен быть на `LI`.</li>
|
||||
<li>В использовании `.tabs > div` особо криминала нет, но нужно учесть, что добавить `DIV` с другим функционалом на этот уровень будет затруднительно. Иначе говоря, такая вёрстка усложняет расширение виджета. Лучше использовать для вкладки класс с префиксом `<div class="tabs-tab">` и, соответственно, селектор `.tabs-tab`.</li>
|
||||
</ul>
|
||||
|
||||
Правильный вариант:
|
||||
|
||||
```html
|
||||
<div id="tabs" class="tabs">
|
||||
<ul class="*!*tabs-headers*/!*">
|
||||
<li><a href="#tabs-1">Вкладка 1</a></li>
|
||||
<li><a href="#tabs-2">Вкладка 2</a></li>
|
||||
<li *!*class="tabs-selected"*/!*><a href="#tabs-3">Открытая..</a></li>
|
||||
</ul>
|
||||
<div *!*class="tabs-tab"*/!* id="tabs-1">Содержимое...</div>
|
||||
<div *!*class="tabs-tab"*/!* id="tabs-2">Содержимое...</div>
|
||||
<div *!*class="tabs-tab"*/!* id="tabs-3" class="*!*tabs-selected*/!*">
|
||||
Посетитель видит содержимое третьей вкладки.
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 2.6 KiB |
|
@ -1,44 +0,0 @@
|
|||
# Ошибки в вёрстке
|
||||
|
||||
[importance 5]
|
||||
|
||||
Посмотрите на вёрстку "табов" (вкладок). Какие ошибки вы в ней видите? Как правильно?
|
||||
|
||||
```html
|
||||
<div id="tabs" class="tabs">
|
||||
<ul class="headers">
|
||||
<li><a href="#tabs-1">Вкладка 1</a></li>
|
||||
<li><a href="#tabs-2">Вкладка 2</a></li>
|
||||
<li><a href="#tabs-3" class="selected">Открытая вкладка</a></li>
|
||||
</ul>
|
||||
<div id="tabs-1">Содержимое в первой вкладке.</div>
|
||||
<div id="tabs-2">Содержимое во второй вкладке.</div>
|
||||
<div id="tabs-3" class="selected">
|
||||
Посетитель видит содержимое третьей вкладки.
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
|
||||
```css
|
||||
.tabs .headers {
|
||||
/* стиль для заголовков вкладок */
|
||||
}
|
||||
|
||||
.tabs .headers .selected {
|
||||
/* стиль для заголовка выбранной вкладки */
|
||||
}
|
||||
|
||||
.tabs > div {
|
||||
/* стиль для обычной вкладки */
|
||||
}
|
||||
|
||||
.tabs > div.selected {
|
||||
/* стиль для выбранной вкладки */
|
||||
}
|
||||
```
|
||||
|
||||
Примерный внешний вид:
|
||||
|
||||
<img src="tabs-example.png">
|
|
@ -48,7 +48,7 @@ HTML-разметка и названия CSS-классов должны отр
|
|||
</div>
|
||||
```
|
||||
|
||||
**Семантическая верстка упрощает поддержку и развитие CSS, упрощает взаимодействие между членами команды.**
|
||||
Семантическая верстка упрощает поддержку и развитие CSS, упрощает взаимодействие между членами команды.
|
||||
|
||||
Такая верстка удобна для организации JS-кода. В коде мы просто ставим нужный класс, остальное делает CSS.
|
||||
|
||||
|
@ -69,21 +69,15 @@ HTML-разметка и названия CSS-классов должны отр
|
|||
</div>
|
||||
```
|
||||
|
||||
Ещё пример -- индикатор загрузки:
|
||||
Или, к примеру, разметка для индикатора загрузки может выглядеть так:
|
||||
|
||||
```html
|
||||
<div class="loader">
|
||||
<div class="indicator *!*loading*/!*">
|
||||
<span class="progress">Тут показывается прогресс</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
Состояние индикатора может быть "в процессе" (loading) или "загрузка завершена" (complete). С точки зрения оформления оно может влиять только на показ внутреннего `span`, но ставить его нужно всё равно на внешний элемент, ведь это -- состояние всего компонента:
|
||||
|
||||
```html
|
||||
<div class="loader *!*loading*/!*">
|
||||
<span class="progress">Тут показывается прогресс</span>
|
||||
</div>
|
||||
```
|
||||
Состояние индикатора может быть "в процессе" (loading) или "загрузка завершена" (complete). С точки зрения оформления оно может влиять только на показ внутреннего `span`, но ставить его нужно всё равно на внешний элемент, ведь это -- состояние всего компонента.
|
||||
|
||||
Из примеров выше можно подумать, что классы, описывающие состояние, всегда ставятся на корневой элемент. Но это не так.
|
||||
|
||||
|
@ -103,80 +97,104 @@ HTML-разметка и названия CSS-классов должны отр
|
|||
</ul>
|
||||
```
|
||||
|
||||
На практике, даже если в начале разработки поставить класс не там -- то, при правильном понимании CSS, рано или поздно он всё равно переместится куда надо, поскольку стилизация открытого/закрытого меню касается также и заголовка.
|
||||
## Префиксы компонента у классов
|
||||
|
||||
Но оптимальнее -- сразу ставить его на правильное место.
|
||||
|
||||
## Префиксы у классов
|
||||
|
||||
Посмотрите, пожалуйста, вёрстку для виджета диалогового окна.
|
||||
Рассмотрим пример вёрстки "диалогового окна":
|
||||
|
||||
```html
|
||||
<!--+ autorun height=100 -->
|
||||
<div class="dialog">
|
||||
<h2 class="title">Заголовок</h2>
|
||||
<div class="content">
|
||||
Содержимое. Имена классов в этой вёрстке опасны.
|
||||
HTML-содержимое.
|
||||
</div>
|
||||
<div class="close">Закрыть</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.dialog .title { стиль заголовка }
|
||||
.dialog .content { стиль содержимого окна }
|
||||
.dialog {
|
||||
background: lightgreen;
|
||||
border: lime 2px solid;
|
||||
border-radius: 10px;
|
||||
padding: 4px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
*!*
|
||||
.dialog .title {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
color: darkgreen;
|
||||
}
|
||||
*/!*
|
||||
|
||||
.dialog .content {
|
||||
padding: 10px 0 0 0;
|
||||
}
|
||||
|
||||
.dialog .close {
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
top: 4px;
|
||||
font-size: 10px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
В этой вёрстке есть серьёзная проблема, которая появится, если в содержимом окна будет элемент с классом `.title`:
|
||||
Диалоговое окно может иметь любое HTML-содержимое.
|
||||
|
||||
```html
|
||||
<div class="dialog">
|
||||
<h1 class="*!*title*/!*">Заголовок</h1>
|
||||
<div class="content">
|
||||
А что будет, если в этом содержимом окажется меню -- да-да, то самое, которое рассмотрели выше, со `<span class="title">` ?
|
||||
|
||||
*!*
|
||||
<h2 class="*!*title*/!*">Привет!</h2>
|
||||
... текст диалога ...
|
||||
*/!*
|
||||
Правило `.dialog .title` применяется ко всем `.title` внутри `.dialog`, а значит -- и к нашему меню тоже. Будет конфликт стилей с непредсказуемыми последствиями.
|
||||
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Такое вполне возможно, ведь диалоговое окно может иметь любое содержимое.
|
||||
|
||||
**В этом случае CSS-правило `.dialog .title` будет применено и к `<h2 class="title">` в содержимом с непредсказуемыми последствиями.**
|
||||
|
||||
Конечно, можно попытаться бороться с этим. Например, нейтрализовать его действие, добавив дополнительное правило `.dialog .content .title`, но это скорее "заплатка", нежели полноценное решение проблемы.
|
||||
|
||||
Ещё один вариант -- жёстко задать вложенность. А именно, использовать класс `.dialog > .title`. Это сработает в данном конкретном примере, но как быть в тех местах, где нужен более глубокий потомок?
|
||||
Конечно, можно попытаться бороться с этим. Например, жёстко задать вложенность -- использовать класс `.dialog > .title`. Это сработает в данном конкретном примере, но как быть в тех местах, где между `.dialog` и `.title` есть другие элементы? Длинные цепочки вида `.dialog > ... > .title` страшновато выглядят и делают вёрстку ужасно негибкой. К счастью, есть альтернативный путь.
|
||||
|
||||
**Чтобы избежать возможных проблем, все классы внутри виджета начинают с его имени.**
|
||||
|
||||
Подходящий вариант:
|
||||
Здесь имя `dialog`, так что все, относящиеся к диалогу, будем начинать с `dialog__`
|
||||
|
||||
Получится так:
|
||||
|
||||
```html
|
||||
<div class="*!*dialog*/!*">
|
||||
<h1 class="*!*dialog-title*/!*">Заголовок</h1>
|
||||
<div class="*!*dialog-content*/!*">Содержимое</div>
|
||||
<h2 class="dialog__title">Заголовок</h2>
|
||||
<div class="dialog__content">
|
||||
HTML-содержимое.
|
||||
</div>
|
||||
<div class="dialog__close">Закрыть</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.dialog-title { стиль загловка }
|
||||
.dialog-content { стиль содержимого окна }
|
||||
.dialog { ... }
|
||||
.dialog__title { стиль заголовка }
|
||||
.dialog__content { стиль содержимого }
|
||||
...
|
||||
</style>
|
||||
```
|
||||
|
||||
В этом случае внутрь `.dialog-content` можно смело помещать другие компоненты со своими классами `..-title`, `..-content` и т.п.
|
||||
Здесь двойное подчёркивание `__` служит "стандартным" разделителем. Можно выбрать и другой разделитель, но при этом стоит иметь в виду, что иногда имя класса может состоять из нескольких слов. Например `title-picture`. С двойным подчёркиванием: `dialog__title-picture`, очень наглядно видно где что.
|
||||
|
||||
Кроме всего прочего, обработка такого CSS будет чуть-чуть быстрее ;) Так как один класс вместо каскада.
|
||||
Есть ещё одно полезное правило, которое заключается в том, что стили должны вешаться на класс, а не на тег. То есть, не `h2 { ... }`, а `.dialog__title { ... }`, где `.dialog__title` -- класс на соответствующем заголовке.
|
||||
|
||||
[smart header="Когда префиксы не нужны?"]
|
||||
Префиксы делают названия классов длиннее, поэтому иногда не хочется их ставить.
|
||||
Это позволяет и избежать конфликтов на вложенных `h2`, и использовать всегда те теги, которые имеют правильный смысл, не оглядываясь на встроенные стили (которые можно обнулить своими).
|
||||
|
||||
Без них можно обойтись в тех случаях, когда внутри элемента заведомо не будет произвольного HTML и других компонент. То есть когда конфликты заведомо исключены.
|
||||
|
||||
С другой стороны, требования имеют свойство расти. Компоненты зачастую вставляются туда, где их не предполагалось. Ваш виджет, написанный для одной задачи или проекта, может быть потом использован совсем в другом месте, где потребуются вложенные компоненты. И тогда заранее предусмотренные префиксы сослужат хорошую службу.
|
||||
[smart header="Без фанатизма"]
|
||||
На практике из этих правил зачастую делают исключения. Можно "вешать" стили на теги и использовать CSS-каскады без префиксов, если мы при этом твёрдо понимаем, что конфликты заведомо исключены.
|
||||
|
||||
Например, когда мы точно знаем, что никакого произвольного HTML внутри элемента (или внутри данного поддерева DOM) не будет.
|
||||
[/smart]
|
||||
|
||||
## БЭМ
|
||||
|
||||
Описанное выше правило именования элементов является частью более общей концепции "БЭМ", которая разработана в Яндексе.
|
||||
|
||||
БЭМ предлагает способ организации HTML/CSS/JS в виде независимых "блоков" -- компонент, которые можно легко перемещать по файловой системе и между проектами.
|
||||
|
||||
Можно как взять часть идеологии, например систему именования классов, так и полностью перейти на инструментарий БЭМ, который даёт инструменты сборки для HTML/JS/CSS, описанных по БЭМ-методу.
|
||||
|
||||
Более подробное описание основ БЭМ можно почитать в статье [](https://ru.bem.info/articles/bem-for-small-projects/), а о системе вообще -- на сайте [](http://ru.bem.info).
|
||||
|
||||
## Итого
|
||||
|
||||
<ul>
|
||||
|
@ -186,8 +204,9 @@ HTML-разметка и названия CSS-классов должны отр
|
|||
|
||||
Это не всегда строго необходимо, но позволяет избежать проблем в случаях, когда компонент может содержать произвольный DOM, как например диалоговое окно с произвольным HTML-текстом.
|
||||
|
||||
Использование `.dialog-title` вместо `.dialog .title` гарантирует, что CSS не применится по ошибке к какому-нибудь другому `.title` внутри диалога.
|
||||
Использование `.dialog__title` вместо `.dialog .title` гарантирует, что CSS не применится по ошибке к какому-нибудь другому `.title` внутри диалога.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue