Приветствую, дорогие друзья! В этом уроке вы узнаете что такое CSS, для чего нужен и как его правильно использовать. Это базовый урок из серии «Для самых маленьких», в котором я постараюсь объяснить наиболее понятным языком основы стилизации документов посредством CSS — Каскадных таблиц стилей (Cascading Style Sheets).
Часть 1. Основы CSS
В данном уроке мы затронем стилизацию документа, созданного с использованием языка разметки, т.е. придание определенной формы, определенного цвета, последовательности, размеров различных элементов и текста на странице, рассмотрим наиболее эффективные приемы работы с каскадными таблицами стилей. Поняв основы, вы сможете самостоятельно правильно и эффективно стилизовать HTML документы.
Обращаю ваше внимание, что в данном руководстве мы будем рассматривать CSS только в контексте использования с HTML документами в веб-браузере. С помощью CSS можно стилизовать и другие документы, использующие различные языки разметки. Например, стилизовать XML в Android приложениях, SVG или различные Desktop Environment в Unix-подобных операционных системах.
Вообще, CSS довольно элементарный формальный язык, который придумали для описания внешнего вида документов. Это говорит о том, что он довольно прост и состоит из самобытных примитивных конструкций, которые не так сложны для изучения. Самое сложное не синтаксис, не правила написания конструкций, а огромное количество CSS свойств для запоминания, которые выполняют различные задачи. Благо, все правила англоязычные с соответствующей смысловой нагрузкой. Простой перевод на наш язык дает понятие о том, что это правило делает и наоборот — при переводе того, что мы хотим добиться определенным свойством на английский язык, велика вероятность того, что мы получим правильное свойство. Это значительно упрощает запоминание CSS правил на интуитивном уровне. Например, если нужно задать фоновый цвет достаточно сделать перевод на английский, в результате чего получаем background-color (отдельные слова в CSS пишутся через дефис).
1.1 Использование CSS в HTML документах
CSS довольно просто использовать в HTML документах. Его можно:
-
Подключить как внешний CSS файл к документу. Для этого достаточно прописать тег <link rel=»stylesheet» href=»путь/до/файла.css»> в теге <head>. Это наиболее распространенный способ подключения таблиц стилей к документу, когда внешнее оформление страниц выносится в отдельный внешний CSS файл.
-
Прописать стили в самом документе, используя тег <style>.
Это менее популярный способ внутренней стилизации, который применяется в особых случаях, когда: А. Базовые стили должны быть моментально интерпретированы браузером до загрузки основных CSS файлов; Б. Когда стили должны быть опционально изменены в процессе работы над веб-сайтом, например, опциональный размер шрифта и другие опции оформления при работе сайта на какой-либо CMS, поддерживающей создание параметров в админ. панели или в других случаях, когда это действительно необходимо.
Пример вывода опции из админки в тело документа:
<style> .class { background-color: <?php echo $bgc_option; ?> } </style>
-
Инлайновое использование CSS свойств в конкретных тегах с помощью атрибута style.
Такой способ внутренней стилизации используется очень редко в особых случаях, когда необходимо: А. Вывести из админ. панели сайта параметры для конкретных тегов; Б. Сделать динамическую стилизацию элементов посредством JavaScript.
Пример инлайнового вывода фонового изображения секции из админ. панели сайта:
<section style="background-image: url(<?php echo $bgi_option; ?>)">
Вывод $bgi_option — простой пример, показывающий что значение свойства задается в админке сайта.
Это довольно топорный способ стилизации элементов на странице, который не стоит использовать в повседневной работе. Только в исключительных случаях, когда это действительно необходимо. Инлайновая стилизация (от слова inline — встроенный) работает только в том элементе, в котором она прописана. Инлайновые стили имеют наибольший приоритет. То-есть если во внешнем файле у вас указана одна картинка для фона, а в инлайновых стилях другая — сработает вторая.
1.2 CSS синтаксис
Как я уже говорил ранее, CSS имеет довольно простой синтаксис. Давайте разберем его.
Правила объявлений настолько просты, что их можно описать в одном предложении. Сначала пишется селектор, который выбирает конкретный элемент на странице, после фигурных скобок пишутся свойства со значениями после двоеточия, а сами свойства отделяются друг от друга точкой с запятой. Это все.
Просто, не правда ли?
Самое сложное в CSS объявлении — селектор. Подробнее узнать о том, как формируются и как используются селекторы вы можете в уроке Все CSS селекторы в одном уроке — это очень важная тема, так как здесь раскрывается вся магия выборки элементов на странице, рекомендую посмотреть этот урок в обязательном порядке всем новичкам.
Вкратце CSS селектор — (от слова select — выбирать) — это конструкция, с которой начинается каждый блок объявлений и которая служит для выборки элемента или однотипных элементов на странице для дальнейшей стилизации. Чаще всего в качестве селектора используется определенный класс тега, например:
//HTML: <div class="my-class"></div> //CSS: .my-class { background-color: #999; }
Здесь селектором выступает класс my-class тега div, который получает необходимое оформление в CSS файле. В данном случае фоновый цвет — серый. Соответственно, если на странице есть несколько тегов (не только div) с классом my-class, все эти элементы получат одинаковое оформление — серый фон цвета #999.
1.3 Каскадирование, наследование и приоритет
Понять принцип каскадирования несложно. Давайте взглянем на пример:
//HTML <div class="parent"> Далеко-далеко за словесными горами в стране. <div class="children"> Далеко-далеко за словесными горами. </div> </div> //CSS .parent .children { color: #666; } .parent { padding: 10px; color: #999; }
Из примера мы видим, что в CSS написан каскад, в котором класс .parent стоит на первом месте, после него через пробел указан дочерний класс .children, который отвечает уже за стилизацию только дочернего элемента. Дочерний тег обязательно должен быть вложен в тег с классом .parent. Если в HTML документе мы вынесем тег .children из тега div с классом .parent, он потеряет свое оформление, так как каскад уже не будет работать, структура нарушена.
Что мы получим в результате нашего примера. Тег с классом .children получит цвет текста #666, так как имеет более длинный каскад, а .parent покрасится в цвет #999. Родительский класс будет иметь внутренние отступы 10px, в то время, как дочерний этих отступов иметь не будет, так как свойство padding не распространяется на дочерние элементы. Однако если мы уберем color: #666; у селектора .parent .children, то его текст покрасится в цвет родителя color: #999;
Каскадирование и наследование позволяют стилизовать конкретные элементы на странице и определять приоритет применяемых стилей. Давайте рассмотрим иерархию приоритетов.
- Самым высоким приоритетом обладают свойства, в конце объявления которых указана конструкция !important. Не важно, какую вложенность имеет селектор, каким образом используются стили — инлайново или подключением внешнего файла, у них будет наибольший приоритет. Я крайне не рекомендую использовать !important при стилизации, так как в процессе поддержки или даже в процессе разработки в дальнейшем обязательно возникнет путаница, которую спасет только рефакторинг стилей. Как показывает практика, всегда есть способ не использовать !important.
Пример использования !important:.my-class { background-color: #999!important; }
- Следующим по значимости приоритетом обладают инлайновые стили, прописанные в самом теге через атрибут style, которые мы рассмотрели ранее: <section style=»background-color: #eee;»>
- Стили, заданные в теге style в самом документе имеют меньший приоритет;
- Еще меньшим приоритетом обладают стили, подключенные к документу как внешний CSS файл посредством тега <link>
- Самый низкий приоритет, окромя стандартных стилей браузера имеют стили родительских селекторов перед дочерними, например:
//HTML <div class="my-class"> <p>Далеко-далеко за словесными горами.</p> </div> //CSS .my-class { margin: 10px; } будет иметь меньший приоритет для дочернего p, чем: .my-class p { margin: 15px; }
В результате тег <p>, находящийся в теге с классом .my-class получит значение свойства margin: 15px.
Стоит также отметить, что количество классов или идентификаторов, а также наличие дополнительных псевдоклассов и конструкций в селекторе повышают приоритет для стилизации:
.my-class.class-2 { margin: 10px; } будет иметь больший приоритет, чем: .my-class { margin: 15px; }
И т.д. по логической цепочке.
И в завершение по приоритетам важно отметить, что стили, идущие в последующих объявлениях ниже по документу также имеют наибольший приоритет. Например:
.my-class { margin: 10px; } будет иметь меньший приоритет, чем идущий после него точно такой-же селектор: .my-class { margin: 15px; }
В результате последний селектор в потоке документа получит значение свойства margin: 15px, так как является наиболее приоритетным. Однако если бы селектор первого объявления был длиннее, значния его свойств несомненно бы превалировали.
Что касается наследования, здесь все просто. Все дочерние элементы наследуют некоторые свойства родителя. Какие именно свойства наследуются предстоит выяснить вам в процессе изучения различных свойств и применении их на практике. Например, цвет текста всегда наследуется потомками, а отступы — нет.
Часть 2. CSS свойства
Я думаю нет смысла перечислять все CSS свойства, так как их очень много и практичней обратиться к справочнику всех CSS свойств. Я рекомендую изучить CSS свойства в справочнике на HTMLBook.
Однако рассмотрим 10 самых используемых CSS свойств в верстке. Я взял 10 больших CSS файлов из своих проектов и отсортировал свойства по частоте использования.
CSS Свойство |
Частота использования |
Описание |
color | 960 раз | Цвет текста элемента: |
background-color | 755 раз | Цвет фона элемента: |
font-size | 524 раза | Размер шрифта: |
opacity | 435 раз | Уровень прозрачности элемента: |
padding | 372 раза | Размер полей внутри элемента: |
width | 356 раз | Ширина блочного элемента, не включая размеры границ и полей: |
margin | 311 раз | Внешние отступы элемента: |
height | 305 раз | Высота блочного элемента, не включая размеры границ и полей: |
font-weight | 280 раз | Насыщенность шрифта: |
text-align | 245 раз | Горизонтальное выравнивание текста: |
Часть 3. Медиа-запросы
Медиа-запросы в CSS — это база для создания отзывчивой верстки, позволяющая стилизовать элементы в зависимости от размера экрана или устройства, на котором отображается веб-сайт. Технически Медиа-запрос — это простое логическое выражение, которое может быть или истинным или ложным. Условиями для такого выражения являются либо параметры устройства, на котором отображается веб-страница, либо размер экрана в пикселах.
В данном руководстве мы рассмотрим базовые возможности медиа-запросов, которые необходимы для адаптивной верстки сайтов и практически полезны.
Медиа-запрос пишется в самом файле стилей или в теле документа (тег style) и начинается с объявления правила @media. Структура медиа запроса довольно проста:
Условием может выступать либо устройство — all (все устройства), screen, print, tv и т.д., либо медиа-функции, которые задают параметры устройства или разрешение экрана, на котором отображается документ.
Наиболее часто используемые медиа-функции определяют именно максимальное и минимальное разрешение экрана устройства:
Здесь устройства с максимальным разрешением экрана 480px или минимальным разрешением 320px будут отображать текст тега с классом .my-class серым. Данное условие я привел для примера, практически оно бесполезно. Чаще всего требуется указать либо только максимальное разрешение, либо только минимальное, в пределах которого будет прменяться свойство.
Кроме всего прочего, как мы видим из примера, функции могут содержать условия and (И), not (НЕ) и only (Для старых браузеров, не поддерживающих медиа-запросы). Нет логического оператора or (ИЛИ), его роль выполняет запятая. Медиа-функции, как мы видим заключают в обычные круглые скобки.
Размещение свойств в медиа-запросе не дает никакого приоритета, поэтому логичней размещать медиа-запросы в конце CSS документа, либо загружать тегом link внешний CSS файл с медиа-запросами после загрузки основных стилей сайта для правильного переопределения последних на разных разрешениях или на различных устройствах.
Часть 4. Рекомендации
Ну и конечно-же мои рекомендации. За всю практику верстки у меня накопились некоторые правила, которыми я с радостью поделюсь.
- Старайтесь использовать только внешние подключаемые CSS файлы. Внутреннюю стилизацию применяйте только если это необходимо для корректного функционирования веб-сайта;
- Старайтесь стилизовать только классы. Не стилизуйте идентификаторы (задаются через id=»решетку» и пишутся через #решетку). Старайтесь меньше стилизовать теги без классов. Например, если вы стилизуете тег h3, а в дальнейшем SEO специалист решит, что заголовок здесь не уместен, обычный div должен иметь такие-же свойства с классом заголовка и отображаться также. Как вариант можно сделать дубликаты HTML тегов в классы, например, .h1, .h2, .h3, .footer, .header, .aside и стилизовать их соответствующим образом;
- Старайтесь стилизовать элементы максимально автономно, сокращайте цепочку каскада до одного блока, чтобы было меньше зависимостей от родительских элементов. Это необходимо для максимально эффективного повторного использования блоков на странице и их модификации в других местах верстки. Но без фанатизма. Не стоит задавать отдельные классы каждому тегу в блоке, если не предполагается его автономное использование. Если вы перенесете блок в другое место страницы, он должен отображаться также и не зависеть от родителя. В этом вам поможет использование какой-либо методологии именования классов. Не важно, будет это БЭМ, методология, либо разработанная на основе вашего личного опыта или простые правила, предложенные мной — это лучше, чем называть классы как попало и строить нелогичные и длинные цепочки классов;
- Старайтесь называть классы тегов в зависимости от того, какую функцию выполняет блок, а не от того, какое в нем будет содержание. Например, если у вас есть секция с отзывами в виде карусели, не стоит называть селекторы, используя слова reviews, otzivy и т.д. Лучше назвать carousel-once, если планируется выводит по одному пункту карусели на странице. В дальнейшем, возможно вы будете использовать эту карусель не только для оформления отзывов, а задействуете этот код например, для вывода списка коллег компании. В таком случае наименование класса reviews будет несколько неуместным;
- Используйте CSS препроцессоры, в этом нет ничего сложного. Мой выбор пал на препроцессор Sass уже довольно давно и я его рекомендую к использованию. У нас есть неплохой урок, в котором я рассказываю как легко пользоваться препроцессором и как он упрощает жизнь: Sass для самых маленьких — подробное руководство;
- Используйте сброс стандартных стилей браузера или нормализацию, которая приводит стандартные стили к общему для всех браузеров знаменателю. Я использую в своих проектах Normalize.css, который входит в состав CSS фреймворка Bootstrap;
- Когда почувствуете, что выполняете слишком много однообразной работы в процессе верстки — переходите к использованию какого-либо CSS фреймворка или разработайте свой с наиболее часто используемыми элементами, это ускорит вашу работу. Я использую в работе только сетку Bootstrap без стилистического оформления кнопок, панелей и прочих элементов. Этого вполне достаточно для эффективной работы. Хорошая адаптивность Bootstrap сетки по умолчанию также радует;
- Самостоятельно экспериментируйте со свойствами. Открывайте CSS справочник и пробуйте. Только так можно наработать опыт, запомнить какое свойство что делает и довести написание стилей документа до автоматизма.
Премиум уроки от WebDesign Master
Другие уроки по теме «Верстка»
- Создание сайта с крутой анимацией скролла (GSAP) | Материалы урока
- Создание красивого сайта с горизонтальным Parallax эффектом | Материалы урока
- Создание сайта портфолио с крутой анимацией | Материалы урока
- Создание красивого сайта с Parallax эффектом при скролле | Материалы урока
- Создание Parallax эффекта на сайте при движении мыши | Материалы урока
- Создание красивого сайта с поддержкой темной темы (HTML, CSS, GSAP) | Материалы урока
- Основы CSS
- Утверждения
- Правило и его составляющие
- Типы элементов в CSS
- CSS Box Model
- Типы отношений элементов в CSS
- Селекторы в СSS
- Специфичность селекторов
- Наследование
- Каскад
- Подходы к написанию CSS
- Проблемы CSS
- Некоторые рекомендации
- БЭМ
- OOCSS
- SMACSS
- Atomic CSS
- AMCSS
- Enduring CSS
- Динамический CSS
- Добавление и удаление классов по условию
- CSS-in-JS
- Вёрстка под различные девайсы
- Viewport
- Виды вёрстки
- Препроцессоры и постпроцессоры CSS
- Препроцессоры
- Постпроцессоры
- Возможности постпроцессоров в деталях
- CSS Modules
Основы CSS
Cascading Style Sheets, CSS — каскадные таблицы стилей; язык таблиц стилей (stylesheet), используемый для представления внешнего вида HTML-документа.
Язык CSS описывает, как элемент должен отображаться на экране.
Документом (document
) называют текстовый файл, структурированный при помощи языка разметки HTML, SVG или XML.
Утверждения
Утверждение, заявление (англ. statement
) — структурный элемент CSS, который начинается с любых непробельных символов и заканчивается первой закрывающей фигурной скобкой или точкой с запятой.
Есть два типа утверждений:
- Набор правил, или проще: правило (англ.
ruleset
,rule
). - At-правило (англ.
at-rule
).
Любое другое утверждение считается недопустимым и игнорируется.
Правило и его составляющие
Правило (англ. rule
) — CSS-утверждение, состоящее из селектора (или группы селекторов) и блока объявлений.
selector1, selector2 /*, ...*/ { property1: value1; property2: value2; /* ... */ }
Cелектор (англ. selector
) используется для выбора элементов страницы. Ниже приведены примеры пяти селекторов:
#menu .title div .parent .child button:hover
Два и более селекторов отделяются друг от друга запятыми и образуют группу селекторов.
p, span, h1 .sister, .brother
Блоком объявлений (англ. declaration block
) называется всё, что находится внутри фигурных скобок. Обычно там находятся объявления.
{ property1: value1; property2: value2; }
Например,
{ font-size: 14px; color: red; }
Объявлением (англ. declaration
) называется пара свойство-значение (англ. property-value
).
Объявления отделяются друг от друга точками с запятой. Если пропущена точка с запятой, то стили могут примениться неправильно или не примениться вовсе.
{ width: 50% /* отсутствие ";" - синтаксическая ошибка */ height: 100%; /* данное правило и все последующие не будут применены, поскольку внутри этого блока объявлений выше имеется синтаксическая ошибка */ }
.article-title, .header-title { color: #ccc; font-size: 18px; }
Блоки объявлений могут быть пустыми.
Блоки объявлений могут быть вложенными, если используются некоторые at-rules (например, @media() {}
.
@media (/*...*/) { div { /*...*/ } }
At-правило
At-правило (англ. at-rule
) — CSS-утверждение, указывающее CSS, как себя вести.
Начинается с символа @ (at
, at sign
) и включает в себя весь следующий блок объявлений или весь код до ;
.
@charset "utf-8"; /* определение набора символов */ @import 'custom.css'; /* импорт таблицы стилей (дополнительный запрос к серверу) */ /* медиазапросы, объявление CSS-правил в зависимости от девайса */ @media screen and (max-width: 1080px) { /* ... */ } /* объявление CSS-правил в зависимости от поддержки браузером */ @supports (display: grid) { /* ... */ } /* объявление и использование шрифта */ @font-face { font-family: "Open Sans"; src: url("/* ... */") format("/* ... */"); } .className { font-family: "Open Sans"; } /* объявление и использование анимации */ @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .className { animation-name: fadeIn; animation-duration: 200ms; }
At-правила могут быть вложенны друг в друга.
@supports (display: grid) { @media screen { /* ... */ } }
Типы элементов в CSS
Блочные и строчные элементы
Блочные элементы — элементы высшего уровня (визуально выглядят как блоки), располагающиеся на странице вертикально и задающие её структуру. Они создают разрыв строки перед элементом и после него, образуя прямоугольную область, по ширине занимающую всю ширину блока-родителя.
Блочные элементы могут содержать как строчные, так и другие блочные элементы.
Блочный элемент <p>
является иключением не должен содержать внутри себя другие блочные элементы (в том числе и p).
Строчные (встроенные) элементы используются для форматирования текстовых фрагментов (кроме <area>
, <img>
). Они не формируют новые блоки контента, не создают разрыв строки вокруг себя. Многие строчные элементы не контролируют поля, отступы, ширину и высоту.
Строчные элементы могут содержать только данные и другие строчные элементы, они не могут содержать блочные элементы. (кроме a)
Блочные и строчные элементы являются основными элементами страницы. С них всё начиналось, и можно сделать практически что угодно, используя только их.
Также есть блочно-строчные элементы, которые обладают смешанной характеристикой: являются встроенным, но могут задавать поля, отступы, ширину и высоту.
Сделать элемент блочным, строчным или блочно-строчным в CSS можно с помощью:
.block { display: block; } .inline { display: inline; } .inline-block { display: inline-block; }
На данный момент существует много других типов элементов, все из которых отражает свойство display
(table
, flex
, grid
и прочие).
Замещаемые и незамещаемые элементы
Замещаемый (replaced) является элемент, представление которого выходит за рамки CSS. Стили CSS не могут влиять на содержимое замещаемых элементов — только на их позиционирование.
Замещаемые элементы.
<iframe>
— содержит веб-страницу, не зависящую от родительской страницы и её стилей.<video>
<img>
<embed>
<input type="image">
В некоторых случаях являются замещаемыми.
<canvas>
<audio>
<option>
<applet>
<object>
Внешний вид и размеры замещаемых элементов могут определяться извне.
Например, img без заданных свойств width
и height
, занимает свой естественный размер.
При изменении одного из этих свойств, второе высчитается автоматически, с учётом пропорций.
Остальные элементы можно отнести к незамещаемым.
CSS Box Model
Каждому HTML-элементу соответствует прямоугольная область, называемая боксом (box).
Структура этой области называется блочной, боксовой моделью (box model).
- content — контент, содержимое; внутренняя область элемента, содержащая текст или другие элементы.
- padding — поля элемента, окружающие контент.
- border — рамки элемента, окружающие поля элемента.
- margin — внешние отступы (пустое пространство вокруг элемента), определяющие расстояние до соседних элементов.
Каждая из этих составляющих имеет какую-то область (area) и границу (edge).
Каждый бокс, являясь прямоугольником, должен иметь ширину и высоту.
Существует два способа задать бокс, от которых зависят его ширина и высота.
border-box
—padding
иborder
входят в указанные в свойствахwidth
иheight
ширину и высоту.content-box
—width
иheight
определяют ширину и высоту только для контента (content width, content height),padding
иborder
дополнительно увеличивают размер бокса.
/* высота бокса: 100px, высота контента: 100px - (16 * 2)px - (4 * 2)px = 60px */ .border-box { box-sizing: border-box; height: 100px; padding: 16px; border: 4px solid; }
/* высота контента: 100px, высота бокса: 100px + (16 * 2)px + (4 * 2)px = 140px */ .content-box { box-sizing: content-box; height: 100px; padding: 16px; border: 4px solid; }
Величина внешних отступов может быть отрицательной, величина остальных составляющих блочной модели — не может.
.class { margin-top: -16px; }
Внешние отступы прозрачны, остальные составляющие могут быть закрашены в какой-то цвет (border-color
для рамок, background-color
для полей и контента.
Типы отношений элементов в CSS
Подраздел относится скорее к DOM (представлению документа в виде дерева). Просто краткое напоминание, что даже у элементов есть отношения:
-
Элемент-предок (ancestor) и элемент-потомок (descendant). Элемент-потомок находится в элементе-предке, но при этом предок может не быть его родителем (потомок может быть вложен в другой элемент, также являющийся потомком для рассматриваемого предка). В примере ниже такая связь наблюдается только между
div
иspan
,div
иimg
. -
Родительский (parent) и дочерний элементы (child). Дочерний элемент находится в родительском и других уровней вложенности между ними нет. Ниже такая связь только между
div
иp
,div
иa
,p
иspan
,a
иimg
. -
Элементы-братья (sibling). Должны иметь одного и того же родителя. Называются смежными (adjacent), если следуют прямо друг за другом. Ниже братьями (причём смежными) являются только
p
иa
. Элементa
называется следующим (following) за элементомp
,p
— предшествующий (preceding) элементуa
(понятия следования и предшествия определены только для смежных элементов). -
Остальные элементы. Хоть они и являются дальними родственниками (как минимум один предок — корень дерева), считаются безотносительными друг к другу. Ниже такими являются
span
иimg
,p
иimg
,span
иa
.
<div> <p> <span></span> </p> <a> <img /> </a> </div>
Способы разметки
Способ разметки в CSS (CSS layout mode, layout) — алгоритм, определяющий позицию и размер блоков на основании того, как они взаимодействуют с их родственными блоками (ancestor, sibling).
Содержащий блок (containing block) — предок рассматриваемого элемента, который может влиять на его размер и позицию. Чаще всего содержащим блоком является элемент-родитель, но не всегда.
Начальный содержащий блок (initial) — <html>
. Размеры начального блока зависят от viewport.
Типы разметки:
- Нормальная, обычная (normal flow) — блочная разметка для блочных элементов (
<div>
,dispalay: block
) и линейная разметка (<span>
,display: inline
) для строчных элементов. Используется по умолчанию. - Табличная (table) для построения таблиц (
<table>
,<tr>
,<th>
,display: table
). - Float-разметка для размещения элемента слева или справа при том, что весь остальной контент оборачивает этот элемент в порядке норамальной разметки. (
float: left
,float: right
). - Позиционированная.
Позиционированный элемент (positioned) — элемент, имеющий вычисленное значениеrelative
,absolute
,fixed
и прочие (но неstatic
) в свойствеposition
.
Любой элемент по умолчанию имеетposition: static
, не считается позиционированным и не реагирует на свойстваtop
,right
,bottom
,left
,z-index
.
Относительно позиционированный элемент (relatively) — элемент, значения свойствtop
,bottom
иleft
,right
которого определяют вертикальное и горизонтальное смещения (offset) от нормального позиционирования соответственно (position: relative
).
Абсолютно позиционированный элемент (absolutely) — элемент, значения свойствtop
,right
bottom
,left
определяют смещения от границ содержащего блока (приposition: absolute
это ближайший позиционированный элемент-предок, приposition: fixed
— начальный содержащий блок). Абсолютно позиционированный элемент удаляется из нормальной разметки документа и не занимает в ней никакого места. Margins добавляются к смещению. - Flexbox-разметка (flexible box).
- Сеточная (grid).
Селекторы в СSS
Селектор (selector) используется для выбора (select) элементов страницы, к которым мы хотим применить стили.
Селекторы подразделяются на простые и составные. В них также включаются псевдоклассы и псевдоэлементы.
Простые селекторы
Селектор по типу выбирает элементы по типу узла.
Селектор по классу выбирает элементы, соответствующие атрибуту class.
Селектор по id выбирает элементы, соответствующие атрибуту id.
Универсальные селекторы выбирают элементы всех типов.
Селекторы атрибутов выбирают элементы на основании наличия указанного атрибута, а также соответствия значения атрибута, если оно указано.
[attr operator value i] {} a[href] {} /* <a> элементы с атрибутом href */ a[href="https://qq.com"] {} /* ...точно соответствующим "https://qq.com" */ a[class^="qq"] {} /* ...начинающимся с подстроки 'qq' */ a[href*="qq"] {} /* ...содержащим подстроку 'qq' */ a[href*="qq" i] {} /* ...содержащим подстроку 'qq' (case insensitive благодаря флагу 'i') */ a[href~="qq" i] {} /* ...содержащим целое слово 'qq' (значение атрибута состоит из слов и пробелов) */ a[href$=".com"] {} /* ...заканчивающимся подстрокой '.com' */
Составные селекторы и комбинаторы
Составной селектор состоит из двух или более простых селекторов, между которыми могут быть комбинирующие операторы — комбинаторы (combinators).
В комбинаторах приоритеты и правила группировки операторов при выборке элементов отсутствуют, поэтому составление выборки осуществляется строго справа налево, от одного простого селектора к другому.
Комбинатор потомков (descendant) A B выбирает элементы, соответствующие селектору B и имеющие предка, соответствующего селектору A.
Комбинатор потомков представлен одним или несколькими пробельными символами (возможно, с переходом на новую строку или даже с комментариями).
.grandfather .son {} .father .son {}
Комбинатор потомков сработает лишь в том случае, если между селекторами нет других комбинаторов. В следующем примере он не применяется, поэтому строки эквивалентны.
.father>.son {} .father > .son {}
Случай, когда селекторов больше двух (например, C A B), означает лишь наличие дополнительного условия. Помимо сказанного выше про A B, у искомых элементов должен также имееться элемент-предок, соответствующий селектору C.
.grandfather .father .son {}
Это точно так же работает как для большего числа селекторов (по индукции), так и для комбинаторов других типов.
Комбинатор детей (child) A > B является частным случаем комбинатора потомков. Он выбирает элементы, соответствующие селектору B и имеющие родительский элемент, соответствующий селектору A.
.grandfather > .father > .son {} .father > .son {}
Комбинатор смежных братьев (adjacent sibling, next sibling) A + B выбирает элементы, соответствующие селектору B, являющиеся смежными братьями с элементами, соответсвующими селектору A, и следующие прямо за ними.
Комбинатор общих братьев (general sibling, subsequent sibling) A ~ B выбирает элементы, соответствующие селектору B, являющиеся братьями с элементами, соответсвующими селектору A, и следующие за ними (не обязательно прямо, между ними могут быть и другие братья).
Рассмотрим несколько примеров, чтобы понять, как работают комбинаторы братьев:
<div class="row"> <div class="cell white"></div> <div class="cell"></div> <div class="cell white"></div> <div class="cell"></div> </div> <style> .row { display: flex; width: fit-content; border: 1px solid; } .cell { width: 50px; height: 50px; } </style> <style> .white + .cell { background: black; } /* Рис. 1 */ .cell + .cell { background: black; } /* Рис. 2 */ .white + .white { background: black; } /* Рис. 3 */ .white ~ .cell { background: black; } /* Рис. 4 */ .cell ~ .cell { background: black; } /* Рис. 5 */ .white ~ .white { background: black; } /* Рис. 6 */ </style>
Рис. 1 Каждое поле, следующее за белым (.white), окрашивается в чёрный.
Рис. 2 Каждое поле, следующее за другим полем, окрашивается в чёрный (все, кроме первого).
Рис. 3 Не найдено белых полей, следующих за белыми.
Рис. 4 Каждое поле, если ранее встречалось хоть одно белое, окрашивается в чёрный.
Рис. 5 Каждое поле, если ранее встречалось хоть одно поле, окрашивается в чёрный.
Рис. 6 Каждое белое поле, если ранее встречалось хоть одно белое поле, окрашивается в чёрный.
Всё это работает так, потому что все поля имеют один класс cell
и у них нет братьев другого класса.
Стоит отметить, что комбинаторы (не считая комбинатора потомков) используются крайне редко, так как могут стать причиной довольно непредсказуемого поведения кода, поскольку при их использовании добавление новых блоков будет сказываеться на стилях других блоков, что может быть особенно заметно, когда в ход вступает специфичность.
Если между селекторами ничего не стоит AB, то происходит их объединение: выбираются элементы, соответствующие обоим селекторам одновременно.
div.white {} .white.cell {} div#body {} p.title {}
Если хотя бы одна часть селектора написана неправильно, то этот селектор полностью игнорируется, на другие селекторы это никак не влияет.
Если между селекторами стоит запятая A, B то они не связаны между собой выбором элементов (в этом случае выборка осуществляется для каждого селектора в отдельности), но ко всем найденным элементам применется один набор стилей. Такой тип связи называется группой селекторов.
Псевдоклассы и псевдоэлементы
Псевдоэлемент — ключевое слово, добавляемое к селектору, позволяющее стилизовать определённую часть выбранного элемента (например, первоя строка).
Псевдоэлементы также позволяют контролировать элементы, находящиеся за пределами документа; позволяют ссылаться на недоступную для получения иным путём информацию (например, полоса прокрутки). Они должны всегда начинаться с двух двоеточий, хоть в большинство браузеров их разрешено использовать и с одним для обратной совместимости:
.field::placeholder { color: #8ab7e5 } /* изменение цвета замещающего текста для input и textarea */ p::before, p::after { content: "♥"; } /* вставка сердечка перед контентом каждого блока p и после него */ p::first-line { color: #8ab7e5 } /* изменение первой строки блочного элемента (в данном случае p) */ p::first-letter { font-size: 24px; } /* изменение первой буквы блочного элемента (в данном случае p) */ *::selection { background: #8ab7e5 } /* изменение цвета выделения текста */ *::-webkit-scrollbar-thumb { background: #8ab7e5 } /* изменение цвета ползунка полосы прокрутки в браузерах на движке webkit */
Псевдокласс — ключевое слово, добавленное к селектору и определяющее его состояние.
Псевдоклассы всегда начинаются с двоеточия. Некоторые из них могут принимать параметры.
input:focus {} /* любое поле ввода, находящееся в фокусе */ option:checked {} /* каждая отмеченная опция */ button:disabled {} /* каждая недоступная кнопка */ link:not(:visited) {} /* каждая непосещённая ссылка */ *:hover {} /* любой элемент при наведении на него */
Если псевдокласс или псевдоэлемент применяются ко всем элементам, то не рекомендуется пропускать универсальный селектор *, иначе может возникнуть путаница.
Селекторы ниже похожи, но выбирают совершенно разные элементы:
div:hover {} /* любой блок div, на который наведён курсор */ div :hover {} /* ~ div *:hover (любой элемент, на который наведён курсор, располагающийся в блоке div) */
С помощью псевдоклассов также можно работать с родительскими и дочерними элементами:
div:empty {} /* каждый блок без дочерних элементов */ div:not(:empty) {} /* каждый блок, имеющий дочерние элементы */ div:first-child {} /* каждый блок, являющийся первым ребёнком */ div:nth-child(3) {} /* каждый блок, являющийся третьим по счёту ребёнком */ div:last-child {} /* каждый блок, являющийся последним ребёнком */ div:only-child {} /* каждый блок, являющийся единственным ребёнком */
Псевдоклассы могут идти последовательно друг за другом:
div:first-child:last-child /* эквивалентно :only-child */
Стоит также отметить, что некоторые псевдоклассы совпадают с атрибутами элементов, поэтому их можно заменить селектором атрибутов. Следующие строки эквивалентны:
button:disabled {} button[disabled] {}
Применение CSS-селекторов в JavaScript (Selectors API)
Selectors API предоставляет методы, с помощью которых можно быстро и просто получить список узлов документа путем сопоставления с группой селекторов.
// возвращает первый найденный Element или null, если совпадений не найдено const element = parentNode.querySelector('selectors'); // возвращает NodeList, содержащий все найденные элементы, или пустой NodeList const elementList = parentNode.querySelectorAll('selectors'); const root = document.querySelector('#root'); const articleTitles = root.querySelectorAll('.article > .title');
Параметр selectors всегда должен быть валидной строкой CSS-селекторов, в противном случае выдаётся исключение SyntaxError.
Специфичность селекторов
Специфичность селекторов (selector’s specificity) определяет приоритетность селекторов в таблице стилей. Чем специфичнее селектор, тем выше его приоритет.
Eсли в выборку несколькими селекторами попадают одни и те же элементы и затрагиваются одни и те же свойства в блоках объявлений, в конечном счёте применяются значения свойств из объявлений более специфичного селектора.
Специфичность представлена четырьмя числами, записанными через запятую A,B,C,D
.
Правила специфичности
- Атрибут style (inline-стиль). Специфичность:
1,0,0,0
. - Атбрибут id. Специфичность:
0,1,0,0
. - Атбрибут class, все остальные атрибуты (кроме
id
) и псевдоклассы (кроме:not
). Специфичность:0,0,1,0
. - Типы элементов и псевдоэлементы. Специфичность:
0,0,0,1
. - Универсальные селекторы и псевдокласс
:not
. Специфичность:0,0,0,0
(нулевая специфичность).
В составных селекторах каждое из четырёх чисел специфичности суммируется отдельно.
Комбинирующие операторы не влияют на специфичность.
* body #root .container ul > li:last-child::after { content: "."; } /* 0,1,2,4 = 0,0,0,0 + 0,0,0,1 + 0,1,0,0 + 0,0,1,0 + 0,0,0,1 + 0,0,0,1 + 0,0,1,0 + 0,0,0,1 */
В группе селекторов специфичность для каждого селектора считается отдельно.
.cell.white, /* 0,0,2,0 = 0,0,1,0 + 0,0,1,0 */ div /* 0,0,0,1 */ { background: #000; }
Стоит отметить, что порядок расположения стилей в class-атрибуте не важен. В примере ниже результат одинаковый:
<p class="title text"></p> <p class="text title"></p>
Почему специфичность нельзя представить одним числом
В примере ниже элемент div
выбирается двумя селекторами, первых из которых представлен одним атрибутом id
, а второй — 11 атрибутами class
.
<div id="identifier" class="a b c d e f g h i j k"></div>
div { width: 100px; height: 100px; } #id { background: red; /* 0, 1, 0, 0 (применится это правило) */ } .a.b.c.d.e.f.g.h.i.j.k { background: green; /* 0, 0, 11, 0 */ }
Если бы специфичность суммировалась в одно число, то 11 атрибутов class
переопределяли бы стили одного id
(11 * 10 > 100
), 11 атбитуров id
переопределяли бы inline-стиль (11 * 100 > 1000
), 11 элементов переопределяли бы один class
, но на самом деле этого не происходит и не должно происходить. Поэтому числа специфичности должны суммируются отдельно.
Наследование
Наследование (Inheritance) — автоматическая передача некоторых свойств (объявлений) элемента-предка его потомкам. В этом случае потомок наследует некоторые свойства предка.
Механизм наследования позволяет разработчикам писать меньше кода. Наследуются не все свойства, поскольку иначе наследование бы только усложнило написание CSS.
Наследуются свойства, задающие параметры отображения текста (все font-*
, большинство text-*
), произношения текста вслух (speak-*
) и отображения списка (list-*
), также наследуются color
, visibility
, cursor
, letter-spacing
, line-height
, white-space
, border-collapse
, border-spacing
и другие, менее популярные свойства.
Почти все остальные свойства не наследуются. Среди них: свойста блочной модели (border-*
, margin-*
, padding-*
, *-width
, *-height
), позиционирования (position
, top
, left
,right
, bottom
, float
), background-*
, transform
, display
, z-index
, text-decoration
и другие.
<div> <p>Notes</p> </div>
div { font-size: 24px; color: red; }
Текст в примере выше, располагающийся в элементе <p>
, будет красным, поскольку свойства font-size
и color
наследуются от div
.
Наследуемое объявление не имеет специфичности (specificity) и важности (importance), о которой будет рассказываться дальше, поэтому его может перекрыть даже правило с универсальным селектором *
, имеющим нулевую специфичность, или любое объявление, по умолчанию указанное в стилях браузера (user-agent declaration).
Если добавить следующее правило в примере выше, то текст станет чёрным несмотря на то, что специфичность селектора *
— 0,0,0,0
, а селектора div
— 0,0,0,1
.
Наследуются не объявленные значения (declared values), а вычисленные значения (computed values).
.parent { font-size: 24px; line-height: 2em; /* 48px (считается от font-size текущего элемента) */ } .child { font-size: 36px; /* в line-height унаследуется не объявленное значение 2em, а вычисленное 2em от 24px = 48px */ }
Наследуемое свойство от ближнего предка перекрывает наследуемое от дальнего. Если бы мы вместо *
использовали body
, то цвет текста остался бы красным, поскольку div
находится ближе к p
, чем body
, и тоже определяет свойство color
.
Наследование тесно связано с древовидной структурой объектной модели CSS.
Наследования обусловлено внутренней реализацией языка. Оно заложено не конкретными свойствами, заданными по умолчанию в стилях, а самим поведением наследуемых свойств.
Чтобы явно унаследовать значение родительского свойства, можно использовать значение inherit
.
Также есть значения initial
и unset
. Первое устанавливает значение, по умолчанию заданное браузером, а в случае его отсутствия работает как inherit
, если свойство наследуемое (naturally inherited). Второе — наоборот: наследует, если свойство наследуемое, в противном случае устанавливает значение браузера.
Использование unset
в примере выше установит красный цвет, initial
— чёрный.
Каскад
Cascading Style Sheets (CSS) переводится как каскадные таблицы стилей. Ключевым словом выступает каскад.
Если несколько селекторов ссылаются на один и тот же DOM-элемент, а в CSS-правилах, привязанных к этим селекторам, затрагивается одно и то же свойство (например, width
, color
), то возникает конфликт: браузеру нужно решить, какое из правил следует применить к элементу, какое из них важнее (приоритетнее). Для этого существует специальный алгоритм, с которым мы познакомимся далее.
Пример конфликта свойства color
:
<div id="foo" class="bar" />
.bar { color: white; } #foo { color: red; } div { color: white; }
Конкретно в данном примере после всех рассчётов стилей будет применён цвет red
. Будем разбираться, почему так.
Каскадом (англ. cascade
) или каскадированием (англ. cascading
) называют *процесс группировки всех таблиц стилей, полученных из разных источников и применяемых к элементу, и разрешения конфликтов между CSS-правилами (как в примере выше.)
Все объявления трёх селекторов ниже будут применены к блоку с классом element
.
<div class="element"></div> <div class="another-element"></div>
div.element { width: 200px; background: #000; } .element { width: 100px; } .another-element, .element { color: #fff; }
Объявления width: 100px
и width: 200px
конфликтуют друг с другом. Решение о том, какое из них применится в конечном счёте, зависит от приоритета, об определении которого рассказывается ниже.
Возможные источники стилей (браузер, автор и пользователь)
Таблицы стилей (англ. style sheets
) могут иметь 3 разных источника (англ. origins
): стили браузера, автора и пользователя.
Стили браузера
Стили браузера, объявления браузера (англ. user-agent declarations
, browser declarations
) — это стили, которые задаются по умолчанию браузером.
Вы можете воспринимать стили браузера как стили по умолчанию, поскольку они работают даже тогда, когда ваш HTML-документ не содержит CSS-объявлений.
Эти стили невозможно отключить, но их очень просто перезаписать.
Некоторые стили браузера можно найти в папке с файлами браузера.
Пример стилей браузера: ссылки <a>
имеют синий цвет и подчёркнуты (англ. underlined
).
Как добиться консистентности в разных браузерах
Каждый браузер задаёт свои стандартные стили, поэтому страница может отображаться в браузерах по-разному и разработчики часто подключают файлы вроде reset.css
или normalize.css
, чтобы сбросить стили браузера.
Стили автора
Стили автора, объявления автора (англ. author declarations
) — стили, подключенные к HTML-документу через тэг <style>
и указанные в этом тэге либо напрямую, либо по ссылке на CSS-файл.
Очевидно, что в данном случае под автором подразумевается разработчик (англ. developer
) данного сайта, который писал код HTML-документа.
Самописные стили в Chrome Dev Tools
Стили, которые вы самостоятельно добавляете в Chrome Dev Tools, также относятся к стилям автора и имеют одинаковый приортитет с теми стилями, что написал разработчик HTML-документа.
Ваши рукописные стили добавляются в новый файл inspector-stylesheet
, который создаёт сам Chrome.
Стили, добавленные в блок element.style {}
в Chrome Dev Tools, также считаются стилями автора и задаются напрямую в атрибуте style
выбранного HTML-элемента.
Стили пользователя
Стили пользователя, объявления пользователя (англ. user declarations
, user styles
) — стили, которые пользователь указывает в настройках браузера.
Ранее пользовательские стили можно было объявить в файле Custom.css
, который можно было найти в папке с файлами браузера, но разработчики решили отключить эту возможность.
В наше время в качетве альтернативы файлу Custom.css сейчас могут использоваться различные расширения Chrome (англ. Chrome extensions
). Например, расширение User CSS.
Раньше же пользовательские стили можно было объявить следующим образом:
- Заходим сюда: chrome://version/
- Копируем
Путь к профилю
и открываем в проводнике.
- Находим папку
User StyleSheets
и в ней файлCustom.css
(сейчас вы его уже не найдёте, а если добавите, то он учитываться не будет). - Изменяем или добавляем новые CSS-объявления в файл.
Пример файла Custom.css
Алгоритм (порядок) каскада
- 1) Важность (Importance)
- 2) Специфичность (Specificity)
- 3) Порядок источника (Source Order)
Будем рассматривать каскад относительно одного HTML-элемента.
- Сперва находятся все CSS-объявления (англ.
declarations
), принадлежащие рассматриваемому элементу. - Если несколько правил конфликтуют друг с другом, то сравнивается их источник (важность). Применяется объявление из более приоритетного источника.
- Если важность совпадает, то сравнивается специфичность. Применяется объявление с более специфичным селектором.
- Если важность и специфичность совпадают, то сравнивается порядок источника. Применяется объявление, которое объявлено позже в коде.
1) Важность (Importance)
Производится упорядочивание объявлений по важности (англ. importance
), зависящей от источника (origin).
Чем ниже по списку ниже, тем выше приоритет.
- Объявления браузера (user-agent declarations).
- Объявления пользователя (user normal declarations).
- Объявления автора (author normal declarations).
- CSS Animations
- Объявления автора с добавлением ключевого слова
!important
(author important declarations). - Объявления пользователя с добавлением ключевого слова
!important
(user important declarations). - Объявления браузера с добавлением ключевого слова
!important
(user-agent important declarations). - CSS Transitions
Важность повышается за счёт ключевого слова !important
.
* { box-sizing: border-box !important; }
Если два конфликтующих правила содержат !important
, то применится более специфичное из них.
#article { padding: 24px !important; } /* применится это правило: id специфичнее класса */ .article { padding: 16px !important; }
Если к одному правилу ключевое слово !important
применен дважды (!important!important
), то важность данного правила не только не изменится, но произойдёт синтаксическая ошибка и правило просто не применится.
#article { padding: 24px !important; } #article { padding: 24px !important!important; } // синтаксическая ошибка "semi-colon expected" (ожидается ";")
2) Специфичность (Specificity)
Если важность и источник совпадают, то сравнивается специфичность селекторов (selector’s specificity), которым принадлежат объявления.
В примере ниже применится объявление width: 200px
, поскольку его селектор специфичнее (подробнее об этом будет дальше).
div.element { /* специфичность: 0,0,1,1 */ width: 200px; /* применится это объявление */ background: #000; } .element { /* специфичность: 0,0,1,0 */ width: 100px; }
3) Порядок источника (Source Order)
Если важность, источник и специфичность совпадают, приоритет объявлений зависит от их расположения в коде, порядка источника (source order). Объявленный позже блок кода (правило, объявление) имеет больший приоритет. Это работает так же, если правила находятся в разных CSS-файлах: приортитетнее считается то правило, чей файл подключен позже.
/* два правила */ p { color: green; } p { color: red; /* применится это объявление (важность, источник, специфичность совпадают и объявлено позже) */ }
/* два объявления */ .article { color: green; color: red; /* применится это объявление */ }
<!-- два файла --> <link href="styles.css" rel="stylesheet" /> <!-- правила (и их объявления) в файле ниже приоритетнее --> <link href="styles2.css" rel="stylesheet />
Значение, полученное в результате каскада, называется каскадным значением (англ. cascaded value
).
Хороший пример проверки знаний каскада
При вычислении каскада сохраняется не только последнее значение, но вся цепочка значений по их приоритету. Таким образом, если самое приоритетное правило будет отключено (например, при помощи JavaScript или Dev Tools в браузере), то вместо него применяется второе по значимости правило. Сейчас разберём большой пример и отсортируем правила в порядке их приоритетности для браузера.
<div id="a" class="a" style="color: pink"> Notes </div>
/* файл со стилями автора */ #a { color: red; } .a { color: orange; } #a#a#a { color: yellow; } #a#a#a { color: green !important!important; } #a { color: lightblue !important; } .a { color: blue !important; } #a { color: purple !important; } div { color: blue; } html { color: yellow; }
Начнём с атрибута style
, далее пойдём по порядку. Будем записывать селекторы в порядке их приоритетов в массив и сортировать его по убыванию приоритета правил.
Для начала предположим, что атрибут style
и весь css
в примере располагаются в коде программы, то есть они написаны программистом (автором) и имеют одинаковый источник, если к правилам не применяется ключевое слово !important
.
- Атрибут
style
имеет специфичность1, 0, 0, 0
. Пока не с чем его сравнивать, просто добавляем в массив: [style
]. - Селектор
#a
имеет тот же источник, что иstyle
. Переходим к рассмотрению (вычислению) специфичности (второй этап алгоритма):0, 1, 0, 0
. Специфичность ниже, чем уstyle
. Значит массив приоритетов: [#a
,style
]. - Селектор
.a
имеет тот же источник, а его специфичность:0, 0, 1, 0
, что ещё ниже, значит имеем массив: [style
,#a
,.a
]. - Селектор
#a#a#a
имеет тот же источник, а его специфичность:0, 0, 3, 0
, что ещё выше#a
и нижеstyle
: [style
,#a#a#a
,#a
,.a
]. - Селектор
#a#a#a!important!important
имеет неправильный синтаксис для правила (поскольку нельзя ключевое слово!important
применить дважды к одному правилу), поэтому правило просто не применится и в массив его добавлять нет смысла. - Селектор
#a!important
имеет источникauthor + important
, что выше всех предыдуших правил, его специфичность:0, 1, 0, 0
. Имеем: [#a!important
,style
,#a#a#a
,#a
,.a
]. - Селектор
.a!important
имеет источникauthor + important
, поэтому он приоритетнее, чем 1)-5). При этом его специфичность:0, 0, 1, 0
, что меньше, чем у 6), а значит массив примет вид: [#a!important
,.a!important
,style
,#a#a#a
,#a
,.a
]. - Селектор
#a!important-2
совпадает с селектором 6), поэтому имеет тот же источник и ту же специфичность, то при этом позже объявлен в коде, а значит считается более приоритетным. Тогда имеем: [#a!important-2
,#a!important
,.a!important
,style
,#a#a#a
,#a
,.a
]. - Селектор
div
имеет источник автора и его специфичность0, 0, 0, 1
, значит он ниже по приоритету, чем все предыдущие селекторы: [#a!important-2
,#a!important
,.a!important
,style
,#a#a#a
,#a
,.a
,div
] - Селектор
html
является родителем всех элементов, а значит и элемента, который мы рассматриваем, при этом свойствоcolor
относится к свойствам текстовых полей, а значит является наследуемым. Наследование не имеет специфичности, поэтому любой из селекторов выше его перебивает по приоритету. Унаследование свойства происходит лишь в том случае, если нет ниодного правила, которое задаёт это свойство напрямую элементу. Таким образом, наследование можно добавить в самый конец нашего массива: [#a!important-2
,#a!important
,.a!important
,style
,#a#a#a
,#a
,.a
,div
,html
].
Как можно увидеть, к элементу применится правило #a!important-2
, то есть фиолетовый цвет (color: purple
).
Скорость выполнения селекторов браузерами
Обработка некоторых селекторов занимает в несколько раз больше (в 5-6 раз) времени, чем других селекторов.
Тем не менее, сейчас в браузерах настолько всё оптимизировано, что данная проблема является одной из наименьших из существующих.
В интернете можно найти множество тестов, которые показывают, что при тысячах элементов на странице даже достаточно сложные селекторы обрабатываются считанные миллисекунды.
Подходы к написанию CSS
- Проблемы CSS
- Некоторые рекомендации
- БЭМ
- OOCSS
- SMACSS
- Atomic CSS
- AMCSS
- Enduring CSS
Проблемы CSS
CSS изначально создавался для стилизации элементов HTML-разметки и ни для чего более. Он обладает огромной гибкостью, позволяя решить любую задачу множеством способов.
- Обращение к элементам происходит при помощи селекторов. Существует множество способов обратиться к одному и тому же элементу.
<div class="header"> <p id="header-title" class="title"></p> </div>
#header-title {} .title {} [class="title"] p {} * {}
- Многие из этих способов можно комбинировать.
.title#header-title p[class="title"] p.title {} .header > * {} .header #header-title {}
- Один селектор может выбирать несколько различных элементов на странице.
<div class="header"> <p class="title"></p> </div> <div class="article"></div> <span class="title article-title"></span> </div>
.title {} /* выберет оба элемента span и p */ div {} /* выберет и header, и article */
-
CSS-правила могут конфликтовать друг с другом и эти конфликты решаются каскадом, но разработчик всё время должен знать важность, специфичность и место в коде для каждого объявления.
-
Всё это усугубляется отсутствием модульности кода. Имеется только глобальная область видимости.
Учитывая всё сказанное выше, возможны случаи, когда стили нового элемента страницы влияют на стили уже существующего элемента, или, наоборот, новый элемент зависит от стилей существующего.
Такой код трудно поддерживать, расширять и над ним практически невозможно работать в команде.
Всё это стало основной предпосылкой к появлению методологий в CSS. Каждая из них по-своему накладывает некоторые ограничения, уменьшая допустимую сложность селекторов, вносит подобие модульности или разделения ответственности (Separation of Concerns).
Некоторые рекомендации
Правила специфичности не так сложны при конкретных селекторах. Но когда селекторов сотни в одном файле, трудно слёту рассчитать (а потом держать это в уме), какой стиль будет применён в итоге или как отельное правило (rule) повлияет на элементы страницы.
Есть некоторые рекомендации, соблюдение которых поможет не только значительно улучшить читабильность кода, но иногда тем или иным образом оптимизировать его:
- Стараться использовать только самые распространённые простые селекторы, покрывающие практически любые случаи — селекторы по классу.
.content p {} /* не очень хорошо */ .content #title {} /* лучше, но есть недочёты (будет сказано дальше) */ .content .title {} /* хорошо */
- То же самое касается и комбинаторов: в большинстве случаев лучше ограничиться комбинатором потомков.
.content ~ .title {} /* результат не очень то предсказуем */ .content > .title {} /* можно иногда использовать, но не все о нём помнят, что сказывается на читаемости кода */ .content .title {} /* хорошо */
- Малая вложенность селекторов. Желательно, не более двух селекторов по классу (
.parent .child
). Это упрощает разбор селектора и ускоряет поиск соответствующих ему элементов как для разработчика, так и для браузера.
.page .content .text-block .title {} /* плохо */ .text-block .title {} /* хорошо */ .text-block .title:hover {} /* тоже хорошо */
- Как можно меньше использовать inline-стили (ведь их практически невозможно переопределить). Вместо этого лучше выносить CSS-код в классы.
<p class="title" style="color:red">Text</p> /* плохо */ <p class="title title--red">Test</p> /* хорошо */
- Стараться избегать использования ключевого слова
!important
, предпочитая ему решение проблемы перекрытия стилей при помощи специфичности. Лишь иногда (но очень редко)!important
является единственным решением проблемы (например, если перекрываются чрезвычайно специфичные стили сторонней библиотеки).
Одной из интересных особенностей CSS является то, что простой селектор можно использовать дважды и специфичность увеличится, а выборка элементов не изменится. Это может помочь, если стили сторонней библиотеки по какой-то причине импортируются позже, чем стили проекта.
<div class="article"></div>
/* перекрыть стили сторонней библиотеки ниже можно специфичностью дублированием селектора: */ .article.article {/* ... */} /* специфичность: 0,0,2,0 */ /* можно и так: */ div.article {/* ... */} /* специфичность: 0,0,1,1 */ /* но лучше не делать вот так: */ div.article {/* ... */ !important} /* важность: author important declaration */ /* стили из сторонней библиотеки */ .article {/* ... */} /* специфичность: 0,0,1,0 */
- При переопределении CSS-правил в своём коде следует больше полагаться на специфичность и меньше на порядок в коде. Тогда приоритет стилей не изменится, если блоки кода в одном файле поменяются местами или CSS-файлы подключатся не в том порядке.
В примере ниже специфичность двух селекторов одинакова и цвет текста зависит от порядка объявления правил в коде. Если поменять правила местами, то применится другой цвет.
<div class="page"> <div class="header"> <p class="title">Notes</p> </div> </div>
.page .title { color: red; } .header .title { color: green; /* применится этот цвет */ }
- При использовании сторонних библиотек стоит обращать внимание именно на порядок подключения CSS-файлов: нужно подключать свою таблицу стилей последней.
<link rel="stylesheet" href="external-lib.min.css> <link rel="stylesheet" href="styles.css>
- Удалять неиспользуемые стили и не подключать большие библиотеки стилей (по типу bootstrap) целиком, если планируется использование лишь малой части (меньше 20%) их функциональности. Это уменьшит время загрузки CSS-файла, его парсинга и построения CSSOM.
Почему лучше избегать использования селекторов по id и использовать селекторы по классу
- Один элемент не может иметь два идентификатора, но может иметь сколь угодно классов.
<!-- это не будет работать! --> <p id="title header-title"></p> <!-- это тем более! игнорирование или ошибка --> <p id="title" id="header-title"></p> <!-- а это работает --> <p class="title header-title"></p>
- Селектор по id выбирает лишь первый элемент на странице.
<div> <p id="title"></p> <!-- игнорирование или ошибка (идентификатор должен быть уникален) --> <p id="title"></p> </div>
- Если есть только селекторы по классу, специфичность вычисляется проще.
.page {} /* 0,0,1,0 */ .content .title {} /* 0,0,2,0 */ .content .title:hover {} /* 0,0,3,0 */
В случае же использования атрибутов id
и class
, количество возможных комбинаций возрастает. Больше комбинаций — больше сложность.
#page #title {} /* 0,2,0,0 (может перезаписать все правила ниже) */ .page #title {} /* 0,1,1,0 */ #page .title {} /* 0,1,1,0 */ .page .title {} /* 0,0,2,0 */
БЭМ
Блок-Элемент-Модификатор (БЭМ, BEM) — самая популярная методология CSS на данный момент.
- Блок (Block) — переиспользуемый элемент сайта.
- Элемент (Element) — некоторая часть блока, не имеющая функционального смысла вне блока.
- Модификатор (Modifier) — свойство блока или элемента, меняющие его внешний вид или поведение.
Возможный синтаксис БЭМ
.block_element-modifier {} /* или */ .block__element--modifier {}
БЭМ в CSS
.page {} /* блок */ .page__content {} /* элемент */ .content {} /* блок */ .articles {} /* блок */ .article {} /* блок */ .article__title {} /* элемент */ .article__title--bold {} /* модификатор */ .article__title--red {} /* модификатор */ .article__image {} /* элемент */ .article__image--small {} /* модификатор */ .article__image--large {} /* модификатор */
БЭМ в SCSS
.page { /* any css for .page */ &__content { /* any css for .page__content */ } } .content {} .articles {} .article { /* any css for .article */ &__title { /* any css for .article__title */ &--bold { /* any css for .article__title--bold */ } &--red { /* any css for .article__title--red */ } } }
Стоит отметить, что любой DOM-элемент в рамках БЭМ может быть и блоком, и элементом одновременно.
В примере ниже div является блоком article и элементом item блока content
<div class="content"> <div class="content__item article"> <p class="article__title"></p> </div> </div>
Преимущества и недостатки БЭМ
Преимущества БЭМ
- Модульность кода и изолированность модулей друг от друга.
- Простая специфичность.
Недостатки БЭМ
- Слишком длинные названия классов.
Пример использования БЭМ с React
import React from 'react'; const articles = [{ title: 'BEM' }, { title: 'React' }]; const renderArticle = (item, index) => ( <div className="article" key={index}> <p className="article__title"> <span className="article__title--red">{`Article #${index}:`}</span> {item.title} </p> <img className="article__image" /> </div> ); const Articles = () => ( <div className="articles"> {articles.map(renderArticle)} </div> ); const render = () => ( <div className="page"> <div className="page__content content"> <Articles /> </div> </div> );
OOCSS
Объектно-Ориентированный CSS (Object Oriented CSS, OOCSS) — подход, использующий преимущества ООП в CSS.
Основная идея заключается в переиспользуемости кода: принцип Don’t Repeat Yourself (DRY).
Объектом в этом подходе выступает любой визуально повторяющийся шаблон, который можно выделить как фрагмент кода.
Элементы страницы задаются объектными классами, являющиеся отдельными объектами в таблицах стилей.
В отличие от многих, подход OOCSS не устанавливает правил наименования классов; не запрещает использовать тэги, id и прочее, что позволяет сочетать его с другими подходами.
Первое правило подхода OOCSS: разделение Структуры и Оформления
Структура (Structure) — совокупность невидимых для пользователя свойств элемента.
Пример структурных свойств: height, width, margin, padding, overflow (размер, позиционирование и прочее).
Оформление (Skin) — совокупность видимых свойств элемента.
Пример свойств оформления: color, font, shadow, gradient.
Другими словами: структура состоит из инструкций о том, как все расположено, а оформление определяет, как выглядит макет.
Такое разделение позволяет размещать копию объекта в любое место сайта, не переопределяя при этом существующие стили.
Эта копия расширяется дополнительными стилями через class-атрибут (часто сразу несколькими классами).
Второе правило подхода OOCSS: разделение Контейнера и Контента
Контентом является любой элемент, расположенный в каком-то другом элементе — контейнере.
Суть заключается в том, чтобы использовать комбинатор потомков как можно реже.
Если контент не зависит от конкретного контейнера, мы можем переиспользовать код чаще.
Например, вместо
.sidebar {} .sidebar .menu {} .sidebar .menu .menu-item {}
можно разделить контейнер и контент следующим образом
.sidebar {} .menu {} .menu-item {}
что даёт возможность использовать меню где-нибудь ещё.
OOCSS в CSS
Ищем повторяющиеся блоки кода:
.button { width: 100px; height: 40px; padding: 4px 8px; background-color: #000; border-radius: 4px; color: #fff; } .button-wide { width: 200px; height: 40px; padding: 4px 8px; background-color: #000; border-radius: 4px; color: #fff; }
<div class="button"></div> <div class="button-wide"></div>
Выносим их в классы:
.skin-button { background-color: #000; border-radius: 4px; color: #fff; } .structure-button { height: 40px; padding: 4px 8px; } .button { width: 100px; } .button-wide { width: 200px; }
<div class="button skin-button structure-button"></div> <div class="button-wide skin-button structure-button"></div>
OOCSS в SCSS
При использовании OOCSS с чистым CSS, атрибут class у DOM-элементов сильно разрастается, но что, если…
@mixin skin-button { background-color: #000; border-radius: 4px; color: #fff; } @mixin structure-button { height: 40px; padding: 4px 8px; } .button { @include skin-button; @include structure-button; width: 100px; } .button-wide { @include skin-button; @include structure-button; width: 200px; }
<div class="button"></div> <div class="button-wide"></div>
Хотя, имея в арсенале миксины, можно сделать ещё лучше (не совсем OOCSS) в этом примере:
@mixin button-defaults { background-color: #000; border-radius: 4px; color: #fff; height: 40px; padding: 4px 8px; } .button { @include button-defaults; width: 100px; } .button { @include button-defaults; width: 200px; }
Преимущества и недостатки OOCSS
Преимущества OOCSS
- Хорошая переиспользуемость кода.
Недостатки OOCSS
- Сильная связанность кода ухудшает его поддержку: классы достаточно общие, могут использоваться повсеместно (нельзя просто изменить их, скорее всего придётся менять разметку).
SMACSS
SMACSS — масштабируемая и модульная архитектура для CSS (Scalable and Modular Architecture for CSS).
Идея заключается в разбиении стилей на слои и тесно связана с принципом разделения ответственности (SoC). Каждый слой выполняет только свои обязательства. Это позволяет улучшить поддержку кода.
Стили разбиваются на 5 слоёв:
- Базовые стили (base rules) — стили основных элементов страницы. Обычно тэги (body, div, input, …), псевдоклассы и псевдоэлементы, атрибуты кроме class и id (изредка class: например, стилизация custom select).
/* базовые стили */ input {} input:focus {} *:hover {} *::selection {}
- Стили макета (layout rules) — стили глобальных элементов страницы (header, footer, sidebar, …), разбивающих страницу на блоки с контентом, состоящие из модулей. Автор подхода предлагает использовать id, чтобы подчеркнуть уникальность элементов, но можно этого не делать. Префикс:
layout-
,l-
илиgrid-
.
#main { width: 40%; } /* глобальный элемент */ #header { width: 100%; } /* глобальный элемент */ /* стили макета ниже навешивается на предков глобальных элементов (например, на body) */ .l-fixed #main { width: 320px; } .l-fixed #header { width: 320px; }
- Стили модулей (modules rules) — стили переиспользуемых блоков страницы. Автор подхода советует избегать здесь тэгов и id. Префикс:
module-
, где module — название модуля.
/* стили модуля */ .article {} .article-title {} .article-img
<div class="article"> <p class="article-title"></p> <img class="article-img" /> <div></div> </div>
- Стили состояния (state rules) — различные состояния модулей и структуры сайта. Автор допускает использование
!important
только в этом разделе. Префикс:is-
.
/* стили состояния */ .button.is-disabled {} .tab.is-active {} #sidebar.is-mobile {} .is-hidden {}
- Стили темы (theme rules) — некоторые дополнительные стили, описывающие, как модули и макет могут выглядеть. Обычно меняются время от времени. Необязательная категория (стили могут быть уже учтены в других категориях).
/* article.css */ .article-title { color: #000; } /* theme.css */ .article-title { color: #ff0000; } /* меняем цвет с чёрного на красный в честь какого-то события */
Обычно на каждый слой отводится отдельный файл: base.scss
, layout.scss
, module-name.scss
, state.scss
, theme.scss
.
Atomic CSS
Атом является мельчайшей частицей вещества.
Атомный CSS (Atomic CSS) — подход, похожий на OOCSS, где в качестве объекта выступает одно объявление (свойство: значение), отражающееся в названии класса.
.Mt-4 { margin-top: 8px; } .Fs-16 { font-size: 16px; } .W-320 { width: 320px; }
<p class="mt-4 fs-16 w-320"></p>
Атомный CSS хорошо подходит для тех, кто хочет писать макет и стили в одном месте.
Тем не менее, вручную писать код с таким подходом не очень удобно, поэтому существует инструмент Atomizer, который рекурсивно обходит html файлы и генерирует весь необходимый css.
Классы: reference
Псевдоклассы: a
— :active
, c
— :checked
, f
— :focus
, h
— :hover
.
Псевдоэлементы: a
— ::after
, b
— ::before
, fl
— ::first-letter
, fli
— ::first-line
, ph
— ::placeholder
.
Комбинаторы: _
— комбинатор потомков, >
— комбинатор детей, +
— комбинатор братьев.
Atomic CSS и CSS
Синтаксис html в случае использования Atomizer следующий
<div class="D(f) Jc(c) Op(0.8):h"></div> <div class="article"> <p class="article_C(red)"></p> </div>
Atomizer при запуске просмотрит html и автоматически сгенерирует css
.D(f) { display: flex; } .Jc(c) { justify-content: center; } .Op(0.8):h:hover { opacity: 0.8; } .article .C(red) { color: red; }
Преимущества и недостатки Atomic CSS
Преимущества OOCSS
- Относительно хорошая переиспользуемость кода (изменил значение в одном месте, изменилось везде).
- Специфичность: лучше, чем использование inline стилей, поскольку здесь стили хранятся в сгенерированных css файлах.
- Можно настроить пользовательские переменные в Atomizer:
{ "1": "1px solid #000", "foo": "2px dotted #f00", }
Недостатки OOCSS
- Названия классов содержат описание объявления, а не суть элемента, что усложняет разработку.
- К пункту выше можно добавить, что атрибуты class могут достигать невероятных размеров с увеличением количества объявлений.
- Управление отображением элемента находится в HTML (отвечающим за разметку), а должно оставаться в CSS.
- Нет встроенной поддержки некоторых вещей, в том числе и grid (нужно либо подключать дополнение или писать самому).
AMCSS
Модули атрибутов для CSS (Attribute Modules for CSS, AMCSS) — подход, использующий атрибуты и их значения вместо классов.
Как и в многих других методологиях, идея AMCSS заключается в логической группировке CSS кода.
- Модули (Modules) — замена классам; описываются атрибутами; похожи на блоки и элементы в БЭМ.
- Вариации (Variations) — различные состояния модулей; представлены значениями атрибутов; похожи на модификаторы в БЭМ.
- Черты (Traits) — коллекция значений, имеющих одну цель; похожи на SUIT utils.
Одной из целей подхода является исправление проблемы БЭМ со слишком длинными названиями классов.
<!-- /* БЭМ * / --> <div class="button button--large button--primary"></div> <!-- /* AMCSS * / --> <div am-Button="large primary"></div>
Префикс am-
добавляется для того, чтобы не было конфликтов с другими атрибутами.
Синтаксис AMCSS
Черты пишутся в camelCase, модули — в PascalCase.
Отношение родитель-ребёнок обозначаются дефисом.
В качестве селектора используется селектор по атрибуту ~=
, выбирающий элементы, содержащие необходимый атрибут и указанные слова (разделённые пробелами) в значении атрибута.
Это позволяет создать поведение, аналогичное классам.
Значения атрибутов, подобно классам, разделяются пробелами, но при этом имеют более широкий спектр допустимых символов.
<div am-traitName="name name2 mobile:name3"></div> <div am-ModuleName></div> <div am-ModuleName-ChildElement></div> <div am-ModuleName="variation"></div>
[am-traitName~="name"] {} [am-traitName~="name2"] {} [am-traitName~="name3"], .breakpoint-mobile [am-traitName~="mobile:name3"] {} [am-ModuleName] { /* Стили модуля (блока) */ } [am-ModuleName~="variation"] { /* Стили вариации модуля ModuleName */ } [am-ModuleName-ChildElement] { /* Стили дочернего элемента модуля ModuleName */ }
Стоит обратить внимание, что вариация не может существовать без базовых стилей модуля.
Любой элемент, удовлетворающий второму селектору в примере ниже, удовлетворяет и первому тоже.
[am-ModuleName] {} /* базовый атрибут и его стили */ [am-ModuleName~="variation"] {}
Черта же не имеет стилей в базовом атрибуте, но зато черты можно смешивать и сочетать в любом месте кода.
[am-traitName~="name"] {}
Существует так же другой синтаксис AMCSS, более близкий к БЭМ, но теряющий некоторые преимущества:
<div am-ModuleName am-ModuleName-variation></div>
[am-ModuleName] {} [am-ModuleName-variation] {}
AMCSS и CSS
Модули и вариации
<div am-Article> <p am-Article-Title="red translucent"></p> </div>
[am-Article] { display: flex; } [am-Article-Title] { margin: 0; } [am-Article-Title~="red"] { color: #ff0000; } [am-Article-Title~="translucent"] { opacity: 0.5; }
Черты
<p am-font="primary" am-color="red"></p>
[am-font~="primary"] { font-size: 18px; font-weight: bold; } [am-color~="red"] { color: #c20606; }
Преимущества и недостатки AMCSS
Подход похож на БЭМ, поэтому обладает теми же преимуществами:
Преимущества AMCSS
- Модульность кода и изолированность модулей друг от друга.
- Простая специфичность. (специфичность у всех атрибутов, в том числе и классов, одинаковая: 0,0,1,0).
- Решена проблема с длинными названиями классов, свойственная БЭМ.
<div class="select__option select__option--first select__option--selected"> <div am-Select-Option="first selected">
- Информация о разнородных стилях не хранится в одной строке, теперь она разбита по атрибутам:
<div class="list__item list__item--even article"> <div am-List-Item="even" am-Article >
- Более широкий спектр допустимых символов в названиях вариаций.
Недостатки AMCSS
- Большая часть всего, что создавалось ранее, делалось на классах.
Принципиально новый подход требует других методов работы не только с CSS, но и с DOM тоже.
Может пострадать поддержка некоторых библиотек. - В случае использования валидатора для проверки корректности кода, нужно также добавлять приставку
data-
, что делает код длиннее.
Если рост количества классов элемента расширяет HTML в ширину, то рост количества атрибутов расширяет его в высоту.
Это не является однозначным минусом или плюсом, но код может сильно разрастить в случае активного использования черт, что может быть не просто исправить.
Enduring CSS
Enduring CSS (eCSS) — выносливый CSS.
Основная концепция: изоляция.
Код Enduring CSS состоит из компонент.
Компонента — изолированная переиспользуемая единица кода, не имеющая зависимостей и контекста. Её можно удалить без риска утечки стилей.
Если нужен компонент, похожий на уже существующий, то всё равно создаётся абсолютно новый компонент. Написанный для одного компонента код не может быть переиспользован в другом, даже если различия компонент незначительны.
Динамический CSS
Давно прошло то время, когда страницы были статическими.
Сейчас на большинстве сайтов элементы появляются и исчезают, меняют свои цвета, размеры и прочие характеристики, реагируя на действия пользователя.
Чтобы добиться динамичности, нужно менять стили.
Существует несколько способов это делать.
Добавление и удаление классов по условию
Многие элементы DOM могут иметь больше одного класса, причём некоторые из этих классов могут быть динамическими (появляются и исчезают из атрибутов по условию).
Чистый JavaScript (работа с DOM)
В примере ниже чёрная кнопка становится красной при наведении мыши (поведение, аналогичное :hover
).
<button class="button"></div> <style> .button { width: 100px; height: 40px; background: #000; } .button--red { background: #f00; } </style> <script> const button = document.querySelector(".button"); button.onmouseenter = () => { button.classList.add('button--red'); } button.onmouseleave = () => { button.classList.remove('button--red'); } </script>
React и библиотека classnames
В React мы не работаем с HTML и DOM напрямую, их заменяют JSX и Virtual DOM.
Это даёт нам возможность проводить вычисления атрибутов, в том числе и атрибута className.
<div className={`article__image ${isLarge ? 'article__image--large' : ''} ${isInverted ? 'article__image--inverted' : ''}`}>
В примере выше картинка статьи может становиться больше или переворачиваться в зависимости от значения переменных isLarge
и isInverted
.
Такой код писать не только не удобно, но нужно ещё и не допусктить появления лишних значений, пробельных символов и переносов строк.
В таких случаях можно прибегнуть к использованию библиотеки classnames
import cx from 'classnames'; /* ... */ const articleImageClasses = cx({ article__image: true, 'article__image--large': isLarge, 'article__image--inverted': isInverted, }); /* или */ const articleImageClasses = cx('article__image', { 'article__image--large': isLarge, 'article__image--inverted': isInverted, });
<div className={articleImageClasses} />
Функция cx принимает сколь угодно параметров.
Если в качестве параметра выступает объект, рассматриваются его ключи и их значения.
Ложные (falsy) значения игнорируются.
Лишние пробельные символы убираются.
CSS-in-JS
CSS-in-JS — подход написания CSS при помощи JavaScript, имеющий множество реализаций.
Как и другие подходы, он вносит идеи о решении проблем в CSS.
В большинстве CSS-in-JS библиотеках есть две функции:
- css — функция, которая принимает CSS в виде текста, генерирует название класса, создаёт новое правило на основании сгенерированного названия и переданных ей стилей, добавляет правило в
<head/>
, возвращает название класса. - styled — функция, генерирующая конкретные DOM-элементы с переданными в неё стилями (стили добавляются при помощи функции
css
).
Встроенные стили
Встроенные стили (inline styles) — стили, которые явно указываются в HTML или JSX.
Встроенные стили в HTML (не относятся к CSS-in-JS, поскольку не могут быть вычислены с помощью JavaScript).
Встроенные стили в React (атрибут style).
/* isHovered, activeColor - переменные */ <p style={{ color: isHovered ? '#f00' : '#000' }} /> <p style={{ color: activeColor }} />
Встроенные стили во Vue (атрибут style с привязкой данных):
/* isHovered, activeColor - переменные */ <p v-bind:style="{ color: isHovered ? '#f00' : '#000' }" /> /* или короче */ <p :style="{ color: isHovered ? '#f00' : '#000' }" /> <p :style="{ color: activeColor }" />
Преимущества и недостатки CSS-in-JS
Изначально в JavaScript и в CSS не было модулей. Со временем в них появилась необходимость, тогда в JavaScript появилась первая модульная система CommonJS, а вслед за ней и стандартизированная версия ECMAScript Modules.
CSS изначально создан для стилизации документов, поэтому в нём так и не появились встроенные модули.
Одна глоабльная область видимости (scope): любой класс на сайте может быть применён к любому элементу.
По мере роста приложения это приводит к проблемам, поэтому и появились методологии.
С помощью этой функциональности решается проблема с названиями.
Преимущества CSS-in-JS:
- Модульность кода.
- Внедрение области видимости в CSS (нужные стили импортируются).
- Явные зависимости.
Как функции css и styled работают внутри
Замечание: в JavaScript есть возможность вызвать функцию следующим образом.
const css = (strings, ...vars) => `{ ${strings} }`; css`magic` // вернёт '{ magic }'
Это называется тэговым шаблоном и работает только с шаблонными строками «.
Первым параметром приходит массив из подстрок, который получается в результате разбиения шаблонной строки её переменными, остальные параметры — сами переменные.
`magic` // 0 переменных, массив подстрок: ['magic'], массив переменных: [] `${2*2} > ${+true}` // 2 переменные, массив подстрок: ['', ' > ', ''], массов переменных: [4, 1]
Сделано это для того, чтобы можно было валидировать и заменять переменные, а затем собрать и вернуть новую строку.
Как работает функция css
:
// произвольная функция генерации хэша const generateRandomHash = () => Math.random().toString(36).substring(7).slice(0, 5); // функция создания правила const createRuleset = (className = '', styles = '') => ` .${className} { ${styles} } `; // получаем строку стилей из параметров тэгового шаблона const getStyles = (strings = [], vars = []) => strings.map((item, index) => `${item}${vars[index] || ''}`).join(''); const css = (strings, ...vars) => { // название класса создаётся на основании хэша, обеспечивая уникальность правила const className = `css-${generateRandomHash()}`; // объединяем параметры тэгового шаблона в строку без изменений (здесь могла быть валидация и правка значений) const styles = getStyles(strings, vars); // генерируется правило const ruleset = createRuleset(className, styles); // создаётся <style /> и помещается в <head> const styleElement = document.createElement('style'); styleElement.textContent = ruleset; document.head.appendChild(styleElement); // возвращиется сгенерированное название класса return className; }; // пример использования функции css const className = css` display: flex; justify-content: center; align-items: center; `; const renderBlock = () => (<div className={className} />);
Как работает функция styled
.
const styled = { div: (...cssParams) => props => (<div className={css(...cssParams)} {...props} />), span: (...cssParams) => props => (<span className={css(...cssParams)} {...props} />), /* ... */ }; // пример использования функции styled.div const Button = styled.div` width: 50px; height: 50px; background: red; `; const renderRedButton = props => (<Button {...props} />);
Вёрстка под различные девайсы
Viewport
Виртуальное окно (virtual window), вьюпорт (viewport) — область окна, в которой пользователю виден контент.
Обычно она не совпадает с отрендеренной страницей, поэтому появляются полосы прокрутки (scrollbars).
<meta name="viewport" content="width=device-width, initial-scale=1">
Свойство width
контролирует размер вьюпорта.
Значение свойства может быть как фиксированным width=700
(от 200 до 10000), так и специальным width=device-width
, которое адаптируется под экран пользователя.
По умолчанию, если метатег отсутствует, браузеры устанавливают своё фиксированное значение (например, width=980
). Это характерно только для мобильных устройств.
В случае фиксированного вьюпорта, медиазапросы @media
перестают работать.
@media (max-width: 320px) {} /* никогда не сработает, если вьюпорт больше 320px */
Свойство initial-scale
отвечает за уровень масштабирования (zoom level), когда страница загружена впервые.
Значение initial-scale=1
означает, что один CSS-пиксель (px) равен одному вьюпорт-пикселю.
Свойства minimum-scale
(0.0 — 10.0), maximum-scale
(0.0 — 10.0), user-scalable
(yes, no) отвечают за возможности масштабирования страницы пользователем. Их рекомендуется не использовать.
Виды вёрстки
Фиксированная, статическая
Фиксированная, статическая (fixed, static) вёрстка постоянна вне зависимости от размеров устройства.
Все элементы занимают строго определённую величину пикселей на странице.
Если элементы не вмещаются, то появлявляются полосы прокрутки.
Если страница слишком велика, то она заполняется элементами не полностью.
Для фиксированной вёрстки используются абсолютные единицы измерения (absolute length units): px
— пиксель (для вёрстки веб-страниц обычно используются они), cm
— сантиметр, in
— дюйм, и другие.
Адаптивная
Адаптивная (adaptive) вёрстка подстраивается под конкретные размеры экранов, не уделяя внимания промежуточным состояниям.
То есть при изменении ширины окна браузера вёрстка сайта перестраивается только в определенные моменты (breakpoints).
Реализуется при помощи медиазапросов @media
одним из двух способов, которые желательно не комбинировать:
- Задание минимальной ширины
@media (min-width: 320px) { .block { width: 200px; } } @media (min-width: 480px) { /* ... */ }
- Задание максимальной ширины
@media (max-width: 1024px) { .block { width: 400px; } } @media (min-width: 960px) { /* ... */ }
Резиновая, Жидкая
Резиновая, Жидкая (Fluid, Liquid) вёрстка использует в стилях относительные единицы измерения (relative length units) и проценты.
%
— процент от значения свойства родителяem
— размер шрифта родительского элементаrem
— размер шрифта корневого элементаvw
— 1% ширины вьюпорта.vh
— 1% высоты вьюпорта.vmin
— меньшее из 1vh и 1vw (сравнение после приведения в пиксели)vmax
— большее из 1vh и 1vw
Отзывчивая
Отзывчивая (responsive) вёрстка подстраивается под все возможные размеры экранов, сочетая в себя возможности резиновой и адаптивной вёрсток.
@media (min-width: 320px) { .block { width: 200vw; } }
Препроцессоры и постпроцессоры CSS
- Препроцессоры
- Постпроцессоры
- Проблемы, которые помогают решить препроцессоры
- Возможности постпроцессоров в деталях
- Сравнение SCSS и PostSCSS
- Сравнение переменных в SCSS и CSS
- Шаблонный селектор, миксин и их различия
- Плагины PostCSS
Препроцессоры
Препроцессор — компьютерная программа, принимающая данные на входе и выдающая данные, предназначенные для входа другой программы.
CSS препроцессор (CSS preprocessor) — программа, принимающая на входе свой собственный синтаксис (syntax) и генерирующая из него чистый CSS на выходе.
Синтаксический сахар (от англ. syntactic sugar) — это дополнения синтаксиса языка программирования, которые не вносят каких-то существенных изменений или новых возможностей, но делают этот язык более читабельным для человека (альтернативное удобное использование того, что было доступно ранее).
Препроцессоры расширяют функционал чистого CSS, добавляя такие опции как: миксины, вложенные правила, селекторы наследования, переменные, функции, циклы и многое другие.
Подобный дополнительный функционал упрощает написание, чтение и поддержку CSS кода.
Популярные препроцессоры:
- SASS
- LESS
- PostCSS
- Stylus
Для использования какого-либо CSS препроцессора нужно установить соответствующего CSS компилятор.
Проблемы, которые помогают решить препроцессоры
-
Модульность. Страндартное at-правило
@import
делает дополнительный запрос к серверу, что является дорогостоящей операцией. Препроцессоры могут переопределять стандартный импорт таким образом, чтобы импортируемый файл вставлялся в исходный без лишних запросов. -
Переиспользование кода. С помощью шаблонных селекторов и миксинов (mixin) можно переиспользовать существующий код.
Постпроцессоры
CSS-постпроцессор делает практически то же самое, что и препроцессор, только на вход вместо специального синтаксиса (например, SASS-подобного) поступает обычный, чистый CSS, а на выход — его изменённая по каким-то правилам версия.
На данный момент PostCSS является единственным постпроцессором.
Для изменения CSS в постпроцессинге используются плагины, у каждого из которого стоит определённая задача по изменению CSS. Каждый плагин представлен сторонним пакетом и подключается отдельно. По умолчанию плагинов нет и PostCSS ничего не делает: лишь возвращает данный ему CSS файл обратно без изменений.
Алгоритм работы PostCSS
- CSS-файл поступает на вход и парсится.
- Первый плагин как-то изменяет CSS.
- …n-ый плагин как-то изменяет CSS…
- Последний плагин как-то изменяет CSS.
- Результат работы последнего плагина преобразуется в строку и записывается в выходной CSS-файл.
Пример: пусть у постпроцессора есть только плагин для минификации CSS. Если отдадим постпроцессору обычный CSS-файл, он его спарсит, минифицирует при помощи плагина и вернёт изменённую версию.
Возможности постпроцессоров в деталях
Сравнение SCSS и PostSCSS
SASS содержит некоторый определённый набор возможностей, которые устанавливаются в виде модуля. Вне зависимости от того, собираетесь вы использовать их все или лишь малую часть из них (например, только переменные или вложенные селекторы), будут установлены все возможности языка.
PostCSS по умолчанию не содержит ничего кроме API, который позволяет подключать плагины, написанные на JavaScript.
Можно ли настроить в PostCSS всё то, что доступно в SCSS? Можно, но каждая возможность будет установлена в виде отдельного плагина (или набора плагинов).
Таким образом, PostCSS даёт вам большую гибкость: у вас появляется возможность установливать только то, что вы собираетесь использовать. Вы можете установить любые плагины из сотен доступных или даже написать свои. Записываем в плюсы PostCSS эффективное использование памяти проекта и гибкость (возможность кастомизации), SCSS не кастомизируется вообще.
С другой стороны, использование PostCSS усложняет настройку проекта, а также приводит к ситуации, что каждый проект содержит свою конфигурацию, что заставляет разработчиков каждый раз привыкать к новому набору плагинов переходя с проекта на проект. Записываем в плюсы SCSS лёгкость настройки и низкий порог вхождения для новых разработчиков на проекте.
Что же выбрать? Выбирайте то, что вам больше подходит на данном проекте в соответствии с плюсами и минусами выше.
Сравнение переменных в SCSS и CSS
SCSS is a preprocessor. That means it is not CSS, but is converted into CSS at ‘compile time’. In the resulting CSS code there is no resemblance to the original SCSS code. Hence you cannot change the variable values at CSS ‘runtime’.
Historically SCSS is a fairly old technique. Actually it dates back to as far as 2007. It was invented by the motivation that CSS lacks certain features amongst which are variables (and nesting and loops and mixins etc.).
CSS variables are a quite recent addition to the CSS standard (The last call working draft seams to be from 2014). They didn’t render SCSS variables useless, because you can do things to SCSS variables which you can’t do with CSS variables (to my knowledge) like color calculations.
On the other hand you can do things with CSS variables that you can’t do with SCSS variables like changing at runtime.
Шаблонный селектор, миксин и их различия
Шаблонный селектор (placeholder selector).
/* шаблонный селектор */ %primary-button-skin { background: #24292e; color: #fff; } .button { @extend %primary-button-skin; width: 200px; } .another-button { @extend %primary-button-skin; width: 160px; }
Миксин (mixin).
@mixin primary-button-skin { background: #24292e; color: #fff; } .button { @include primary-button-skin; width: 200px; } .another-button { @include primary-button-skin; width: 160px; }
- Определения шаблонных селекторов и миксинов не попадают в CSS после компиляции.
- В шаблонные селекторы нельзя передавать параметры, в миксины — можно.
@mixin primary-button-skin($color) { background: #24292e; color: $color; } .button { @include primary-button-skin(#fff); }
- Миксины создают повторяющийся код, поскольку просто вставляют своё содержимое. (включаются)
.button { background: #24292e; color: #fff; width: 200px; } .another-button { background: #24292e; color: #fff; width: 160px; }
Шаблонные селекторы выносят код в отдельную группу селекторов, не создавая дубликатов кода. (наследуются)
.button, .another-button { background: #24292e; color: #fff; } .button { width: 200px; } .another-button { width: 160px; }
Плагины PostCSS
Браузер — прикладное ПО, созданное для просмотра веб-страниц, веб-документов, файлов и их каталогов; для управления веб-приложениями и многого другого.
Поставщики браузеров (browser vendors), вендоры — создатели веб-браузеров.
Вендорные префиксы (vendor prefixes), браузерные префиксы добавляют поддержку экспериментальных браузерных технологий, которые на данный момент не входят в стандарт.
Самые популярные браузеры используют следующие префиксы:
-webkit-
— Chrome, Safari, новые версии Opera.-moz-
— Firefox.-o-
— старые версии Opera.-ms-
— IE, Edge.
Стоит так же отметить, что каждый браузер реализует свойства с префиксами по-своему, поэтому поведение этих свойств в различных браузерах может не совпадать.
Плагин Autoprefixer добавляет браузерные префиксы к правилам CSS, используя значения сайта Can I Use.
.animated-element { -o-transition: all 4s ease; -webkit-transition: all 4s ease; -ms-transition: all 4s ease; -moz-transition: all 4s ease; transition: all 4s ease; }
Плагин Preset Env позволяет конвертировать современный, ещё не поддерживаемый целевыми браузерами CSS код в то, что они смогут понять, определяя необходимые полифиллы на основании целевых браузеров или сред выполнения.
Ниже представлены возможности, которые ещё не попали в стандарт, но уже могут использоваться с плагином:
a { all: initial; /* сбрасывает все свойства элементов a */ } /* псевдонимы (aliases) для at-rules */ @custom-media --mobile (max-width: 420px); @media (--narrow-window) {} @custom-selector :--heading h1, h2, h3, h4, h5, h6; article :--heading {} /* пользовательские свойства */ .title { --size: 20px; font-size: var(--size); }
Плагин cssnano позволяет значительно оптимизировать CSS код (иногда в несколько раз).
До работы плагина
h1::before, h1:before { /* normalize selectors */ margin: 10px 20px 10px 20px; /* reduce shorthand even further */ color: #ff0000; /* reduce color values */ font-weight: 400; font-weight: 400; /* remove duplicated properties */ background-position: bottom right; /* reduce position values */ background: linear-gradient(to bottom, #ffe500 0%, #ffe500 50%, #121 50%, #121 100%); /* reduce gradient parameters */ min-width: initial; /* replace initial values */ } @charset "utf-8"; /* correct invalid placement */
После
@charset "utf-8";h1:before{margin:10px 20px;color:red;font-weight:400;background-position:100% 100%;background:linear-gradient(180deg,#ffe500,#ffe500 50%,#121 0,#121);min-width:0}
Плагин Pre CSS — пак PostCSS плагинов, позволяющий использовать SASS-подобный синтаксис.
$gray: #24292e; .menu { &__bg { background: $gray; } }
Stylelint — мощный CSS линтер, который предупреждает об ошибках в CSS, делает замечания о том, что можно сделать лучше, вносит соглашения по стилю кода внутри проекта.
Stylelint использует под капотом PostCSS для парсинга кода и существует в виде PostCSS плагина.
Таким образом, PostCSS изначально ближе к чистому CSS, но с помощью определённых плагинов может обладать той же функциональностью, что и препроцессоры.
CSS Modules
CSS Modules помогают решить проблему наименования классов в проекте.
Пусть есть несколько разных компонент, которые имеют элементы одинакового назначения. Например, название (title).
/* Article.css */ .title { /* ... */ } .description { /* ... */ }
/* MenuItem.css */ .title { /* ... */ } .icon { /* ... */ }
Если мы просто добавим эти стили, то они сольются друг с другом, поскольку названия классов совпадают.
Ситуация усугубляется, если проект огромный, и мы просто не знаем всех существующих в нём классов.
Чтобы избежать конфликтов, приходится писать код одним из следующих способов.
.article-title {} /* или */ .article .title {} /* или */ .article__title {}
Но есть и другое решение.
CSS-модуль (CSS Module) — CSS-файл, в котором все имена классов и анимаций по умолчанию ограничены локально, то есть в файле содержатся стили какого-то конкретного компонента (блока, модуля).
CSS-модуль поступает на вход компилятору CSS-модулей (CSS Modules Compiler), который по заданному шаблону изменяет все названия классов и возвращает CSS-файл с изменениями.
/* Article.css */ /* было */ .title {} /* [local] */ /* стало */ .Article__title___gt5k {} /* [name]__[local]___[hash:base64:4] */ /* Header.css */ /* было */ .title {} /* стало */ .MenuItem__title___r3vw {}
Использовать сгенерированные названия в коде вручную не нужно.
При импорте CSS файла, импортируется объект, содержащий соответствия между оригинальными именами классов и их модифицированными версиями:
export default { 'title': 'Article__title___gt5k', /* ... */ };
Тогда на примере React
import styles from './Article.css' const renderTitle = () => ( <p className={styles.title}>Title</p> );
В результате в HTML будет
<p class="Article__title___gt5k">Title</p>
Если использовать такой подход во всём проекте, то имена классов в разных файлах не будут конфликтовать друг с другом и это сильно упростит написание CSS кода.
CSS-модули позволяют композицию классов (в том числе и множественную) с помощью свойства composes
.
.classA { /* ... */ } .classB { /* ... */ } .classC { composes: classA classB; } .classD { composes: classC; }
Композиция из других CSS-модулей также доступна:
.classB { composes: classA from "./style.css"; }
Не знаете, как работают элементы CSS? Пора освоить все виды селекторов и позиционирование на странице. Разбираем наглядные примеры.
CSS (аббревиатура от Cascading Style Sheets – каскадные таблицы стилей) – язык, который используем для оформления стиля HTML-файла и сообщения браузеру, как отображать элементы на странице.
Речь пойдёт исключительно о стилях документов HTML, хотя CSS применяют и для других XML-документов.
Файл CSS содержит правила CSS.
Каждое правило состоит из 2 частей:
- селектор
- блок объявлений
Селектор CSS – строка, которая идентифицирует элементы (один или несколько) на странице в соответствии со специальным синтаксисом, о котором скоро поговорим.
Блок объявлений содержит одно или несколько объявлений, которые состоят из свойства и значения.
Больше в CSS ничего нет.
Как выглядит CSS
Набор правил CSS состоит из cелектора и объявления.
Объявление содержит правила, каждое из которых состоит из свойства и значения.
В этом примере селектор p
применяет одно правило, которое устанавливает значение 20px
для свойства font-size
:
p { font-size: 20px; }
Правила следуют одно за другим:
p { font-size: 20px; } a { color: blue; }
Селектор распространяется на один или больше элементов:
p, a { font-size: 20px; }
и на теги HTML, как указано выше, или элементы HTML, которые содержат конкретный атрибут class
– .my-class
, или элементы HTML с конкретным атрибутом id
– #my-id
.
Продвинутые селекторы CSS выбирают элементы, атрибут которых соответствует конкретному значению, и элементы, которые отвечают псевдоклассам (подробнее об этом позже).
Точка с запятой
Каждое правило CSS заканчивается точкой с запятой. Точки с запятой обязательны только для последнего правила. Для последовательности рекомендуем использовать их после каждого правила. Тогда не столкнётесь с ошибкой, если добавите другое свойство и забудете добавить точку с запятой в предыдущей строке.
Добавление CSS на страницу HTML
CSS прикрепляется к HTML-странице тремя способами.
1: Использование тега link
С помощью тега link
подключаем файл CSS. Это предпочтительный способ использования CSS. Один файл CSS распространяется на все страницы сайта. Поэтому изменение одной строки в этом файле влияет на представление всех страниц сайта.
Для использования этого метода добавляем тег link
с атрибутом href
, который указывает на нужный файл CSS. Делаем это внутри тега head
, а не внутри тега body
:
<link rel="stylesheet" type="text/css" href="myfile.css">
Атрибуты rel
и type
также обязательные, поскольку они сообщают браузеру, на какой тип файла ссылаться.
2: Использование тега style
Вместо того, чтобы использовать тег link
для указания отдельной таблицы стилей, которая содержит наш CSS, добавляем CSS непосредственно внутри тега style
. Синтаксис такой:
<style> ...наш CSS... </style>
Когда используем этот метод, избегаем создания отдельного файла CSS. Это хороший способ поэкспериментировать перед «формализацией» CSS в отдельном файле.
3: Встроенные стили
Встроенные стили – третий способ добавления CSS на страницу. Добавляем атрибут style
к любому тегу HTML и включаем в него CSS.
<div style="">...</div>
Пример:
<div style="background-color: yellow">...</div>
Селекторы
Селектор связывает одно и более объявлений с одним или несколькими элементами на странице.
Базовые селекторы
Предположим, отобразим слова в элементе p
на странице жёлтым цветом.
Для указания этого элемента используем селектор p
, который охватывает все теги p
на странице. С помощью несложного правила CSS достигаем цели:
p { color: yellow; }
Каждому тегу HTML соответствует селектор, например: div
, span
, img
.
Если селектор CSS соответствует нескольким элементам, изменение затронет все элементы на странице.
Для привязки стиля к необходимому элементу на странице используются два атрибута HTML-элементов: class
и id
.
Различие между ними состоит в том, что внутри HTML-документа одно и то же значение class
используется для одного или нескольких элементов, а id
только один раз. Как следствие, с использованием классов CSS выбираются элементы с двумя и более конкретными именами классов, что невозможно с помощью идентификаторов.
Классы обозначаются с помощью символа .
, в то время как для идентификаторов используется символ #
.
Пример использования класса:
<p class="dog-name"> Роджер </p> .dog-name { color: yellow; }
Пример использования идентификатора:
<p id="dog-name"> Роджер </p> #dog-name { color: yellow; }
Сочетание селекторов
Выбор элемента с помощью класса CSS или идентификатора
Выберем целевые элементы, к которым прикрепляется класс или идентификатор.
Пример использования класса:
<p class="dog-name"> Роджер </p> p.dog-name { color: yellow; }
Пример использования идентификатора:
<p id="dog-name"> Роджер </p> p#dog-name { color: yellow; }
Ориентация на составные классы
Уже в курсе, как выбрать целевой элемент с помощью конкретного класса с использованием .class-name
. Теперь отметим элемент с двумя или более классами: объединим имена классов и разделим точкой, без пробелов.
Пример:
<p class="dog-name roger"> Роджер </p> .dog-name.roger { color: yellow; }
Объединение классов и идентификаторов
Таким же образом объединяем класс и идентификатор.
Пример:
<p class="dog-name" id="roger"> Роджер </p> .dog-name#roger { color: yellow; }
Группировка селекторов
Скомбинируем селекторы, чтобы применять одни и те же объявления к нескольким селекторам. Для этого разделяем их запятой.
Пример:
<p> Мою собаку зовут: </p> <span class="dog-name"> Роджер </span> p, .dog-name { color: yellow; }
Добавим отступы в этих объявлениях для понятности:
p, .dog-name { color: yellow; }
Следование по дереву документа с помощью селекторов
Создадим конкретный селектор из комбинации элементов, чтобы следовать древовидной структуре документа. Например, тег span
вложен в тег p
. Теперь выберем его без применения стиля к тегу span
, который не включён в тег p
:
<span> Здравствуйте! </span> <p> Мою собаку зовут: <span class="dog-name"> Роджер </span> </p> p span { color: yellow; }
Посмотрите, как использовали пробел между двумя токенами p
и span
.
Это работает даже при многоуровневой вложенности элемента справа.
Для определения зависимости первого уровня используем символ >
между двумя токенами:
p > span { color: yellow; }
В этом случае, если span
не первый потомок элемента p
, новый цвет не применяется. Стиль будет применяться к прямым потомкам:
<p> <span> Это жёлтый </span> <strong> <span> Это не жёлтый </span> </strong> </p>
Одноуровневые селекторы стилизуют элемент, только если ему предшествует конкретный элемент. Делаем это с помощью оператора +
.
Пример:
p + span { color: yellow; }
Это назначит жёлтый цвет элементам span
, которым предшествует элемент p
:
<p>Это абзац</p> <span>Это жёлтый промежуток</span>
Селекторы атрибутов
В этом разделе проанализируем селекторы атрибутов. Поговорим о селекторах псевдоклассов и селекторах псевдоэлементов в следующих двух разделах.
Селектор присутствия атрибута
Первый тип селектора – атрибут присутствия атрибута.
Проверим, содержит ли элемент атрибут, используя синтаксис []
. p[id]
выберет все теги p
на странице, которые имеют атрибут id
, независимо от значения:
p[id] { /* ... */ }
Точные селекторы значений атрибутов
Внутри скобок проверяем значение атрибута с помощью =
, и CSS будет применяться только в том случае, если атрибут соответствует указанному значению:
p[id="my-id"] { /* ... */ }
Соответствие части значения атрибута
Хотя =
проверяет точное значение, существуют другие операторы для проверки:
*=
содержит ли атрибут часть^=
начинается ли атрибут с части$=
заканчивается ли атрибут частью|=
начинается ли атрибут с части и после него идёт тире (например, в классах) или просто содержит часть~=
содержится ли часть в атрибуте, но отделена пробелами от остальных
Все упомянутые проверки чувствительны к регистру.
Если добавите i
непосредственно перед закрывающей скобкой, проверка не будет чувствительна к регистру. Это поддерживается многими браузерами, но не всеми, проверьте.
Псевдоклассы
Псевдоклассы – предопределенные ключевые слова, которые используются для выбора элемента на основании его состояния или для определения целевого дочернего элемента.
Начинаются с одного двоеточия :
.
Используются как часть селектора, и полезны для стилизации активных или посещённых ссылок. Например, для изменения стиля при наведении, фокусе или выборе первого потомка или нечётных строк.
Рассмотрим рядовой пример. Вы хотите стилизовать ссылку, поэтому создаёте правило CSS для элемента a
:
a { color: yellow; }
Это, кажется, работает, пока не нажмёте одну ссылку. Ссылка возвращается к предопределенному цвету (синему) при нажатии на неё. Затем, когда открываете ссылку и возвращаетесь на страницу, ссылка синего цвета.
Почему это происходит?
Потому что ссылка при нажатии изменяет состояние: переходит в состояние :active
. И когда ссылку посетили, она становится :visited
. Навсегда, пока пользователь не очистит историю просмотров.
Итак, чтобы правильно сделать ссылку жёлтой во всех состояниях, напишем
a, a:visited, a:active { color: yellow; }
:nth-child()
заслуживает отдельного упоминания. Применяется для обозначения нечётных или чётных потомков: :nth-child(odd)
и :nth-child(even)
.
Часто это используется в списках для отличия нечётных линий от чётных:
ul:nth-child(odd) { color: white; background-color: black; }
Псевдоэлементы CSS
Псевдоэлементы используются для стилизации определённой части элемента.
Начинаются с двойного двоеточия ::
.
Иногда встречаются с одним двоеточием, но этот синтаксис поддерживается по причине обратной совместимости. Используйте два двоеточия, чтобы отличить их от псевдоклассов.
::before
и ::after
, вероятно, самые используемые псевдоэлементы.
Применяются для добавления содержимого до или после элемента, например, иконки.
Теперь пример. Допустим, хотим, чтобы размер первой строки абзаца увеличился, что типично для типографии:
p::first-line { font-size: 2rem; }
Или, может быть, хотим, чтобы первая буква была жирнее:
p::first-letter { font-weight: bolder; }
::after
и ::before
менее интуитивны. Указываем свойство content
для вставки содержимого любого типа после или перед элементом:
p::before { content: url(/myimage.png); } .myElement::before { content: "Эй, эй!"; }
Позиционирование
Позиционирование – это то, с помощью чего в CSS мы определяем, где элементы появляются на экране и как они появляются.
Статическое позиционирование
Это значение по умолчанию для элемента. Статически расположенные элементы отображаются в нормальном потоке страниц.
Относительное позиционирование
Если установите position: relative
для элемента, то сможете изменить его расположение со смещением, используя свойства
top
right
bottom
left
которые называются свойствами смещения. Принимают значение длины или процент.
Смотрите пример на Codepen. Создали родительский контейнер, дочерний контейнер и внутреннее поле с текстом:
<div class="parent"> <div class="child"> <div class="box"> <p>Test</p> </div> </div> </div>
и CSS, который добавляет цвета и поля, но не затрагивает позиционирование:
.parent { background-color: #af47ff; padding: 30px; width: 300px; } .child { background-color: #ff4797; padding: 30px; } .box { background-color: #f3ff47; padding: 30px; border: 2px solid #333; border-style: dotted; font-family: courier; text-align: center; font-size: 2rem; }
вот результат:
Попробуйте добавить любое из свойств, которые упоминали раньше (top
, right
, bottom
, left
), в .box
, и ничего не произойдёт. Положение static
.
Теперь, если установим position: relative
в блок, сначала кажется, что ничего не изменилось. Но теперь элемент перемещается с использованием свойств top
, right
, bottom
, left
. И теперь положение изменяется относительно элемента, содержащего его.
Например:
.box { /* ... */ position: relative; top: -60px; }
Отрицательное значение для top
заставит блок двигаться вверх относительно контейнера.
Или же
.box { /* ... */ position: relative; top: -60px; left: 180px; }
Обратите внимание, как пространство, которое занимает блок, сохраняется в контейнере, как будто ещё на месте.
Ещё одно свойство, которое теперь работает, это z-index
, и изменяет размещение по оси z.
Абсолютное позиционирование
Установка position: absolute
для элемента удалит его из потока документа.
Помните наблюдение при относительном позиционировании, что пространство, первоначально занимаемое элементом, сохраняется даже при перемещении элемента?
При абсолютном позиционировании как только устанавливаем position: absolute
в .box
, его исходное пространство теперь разрушено, и только исходная точка (координаты x, y) остаётся прежней.
.box { /* ... */ position: absolute; }
Теперь перемещаем блок по своему усмотрению, используя свойства top
, right
, bottom
, left
:
.box { /* ... */ position: absolute; top: 0px; left: 0px; }
или
.box { /* ... */ position: absolute; top: 140px; left: 50px; }
Координаты указаны относительно ближайшего контейнера, который не static
.
Это означает, что если добавим position: relative
для элемента .child
и установим top
и left
в 0, блок появится не в верхней левой границе окна, а на координатах 0, 0 элемента .child
:
.child { /* ... */ position: relative; } .box { /* ... */ position: absolute; top: 0px; left: 0px; }
Как уже видели, .child
статический по умолчанию:
.child { /* ... */ position: static; } .box { /* ... */ position: absolute; top: 0px; left: 0px; }
Как и для относительного позиционирования, используется z-index
, чтобы изменить положение по оси z.
Фиксированное позиционирование
Как и в случае абсолютного позиционирования, когда элементу назначается position: fixed
, он удаляется из потока страницы.
Отличие от абсолютного позиционирования CSS заключается в следующем: элементы теперь всегда расположены относительно окна, а не первого нестатического контейнера.
.box { /* ... */ position: fixed; }
.box { /* ... */ position: fixed; top: 0; left: 0; }
Другое отличие состоит в том, что прокрутка не влияет на элементы. Если поместить «липкий» элемент где-нибудь, прокрутка страницы не удалит его из видимой части страницы.
Липкое позиционирование
Несмотря на то, что предыдущие значения вводили уже давно, это добавили недавно. И оно по-прежнему относительно не поддерживается (смотрите caniuse.com).
Компонент iOS UITableView – то, что приходит на ум, когда думаешь о position: sticky
. Знаете, когда прокручиваешь список контактов, и первая буква закреплена сверху, чтобы знать, что просматриваешь контакты на эту конкретную букву?
Раньше использовали JavaScript для подобной имитации, а теперь этот подход поддерживается в CSS нативно.
Обтекание и его отмена
Обтекание было важной темой в прошлом.
Использовалось в куче хаков и творческих приёмов, потому что этот способ, вместе с таблицами, на самом деле давал реализовать некоторые макеты. Раньше использовали обтекание боковой панели слева, например, чтобы показывать её в левой части экрана. И добавляли отступы к основному контенту.
К счастью, времена изменились, и сегодня Flexbox и Grid помогают с макетом. float
вернулся к первоначальному назначению: размещение содержимого на одной стороне элемента контейнера и отображение одноуровневых элементов вокруг него.
Свойство float
поддерживает три значения:
left
right
none
(по умолчанию)
Скажем, блок содержит абзац с некоторым текстом, а абзац также содержит изображение.
Вот код:
<div class="parent"> <div class="child"> <div class="box"> <p>This is some random paragraph and an image. <img src="https://via.placeholder.com/100x100" /> The image is in the middle of the text. The image is in the middle of the text. The image is in the middle of the text. The image is in the middle of the text. The image is in the middle of the text. The image is in the middle of the text. The image is in the middle of the text. The image is in the middle of the text. The image is in the middle of the text. </p> </div> </div> </div> .parent { background-color: #af47ff; padding: 30px; width: 500px; } .child { background-color: #ff4797; padding: 30px; } .box { background-color: #f3ff47; padding: 30px; border: 2px solid #333; border-style: dotted; font-family: courier; text-align: justify; font-size: 1rem; }
и внешний вид:
Как видите, нормальный поток по умолчанию считает изображение встроенным и освобождает место для него в самой строке.
Если добавим float: left
к изображению и некоторые поля:
img { float: left; padding: 20px 20px 0px 0px; }
результат такой:
а это то, что получаем, когда применяем float: right
и соответственно корректируем поля:
img { float: right; padding: 20px 0px 20px 20px; }
Плавающий элемент удаляется из нормального потока страницы, а остальное содержимое обтекает его.
Смотрите пример на Codepen
Не ограничиваемся плавающими изображениями. Здесь заменим изображение на элемент span
:
<div class="parent"> <div class="child"> <div class="box"> <p>This is some random paragraph and an image. <span>Some text to float</span> The image is in the middle of the text. The image is in the middle of the text. The image is in the middle of the text. The image is in the middle of the text. The image is in the middle of the text. The image is in the middle of the text. The image is in the middle of the text. The image is in the middle of the text. The image is in the middle of the text. </p> </div> </div> </div> span { float: right; margin: 20px 0px 20px 20px; padding: 10px; border: 1px solid black }
и вот результат:
Отмена обтекания
Что происходит, когда плавающий элемент не один?
Если сталкиваются два плавающих изображения, по умолчанию они складываются одно за другим, горизонтально. Пока не закончится место, и они начнут укладываться на новую линию.
Скажем, было три встроенных изображения внутри тега p
:
Если добавим float: left
к этим изображениям:
img { float: left; padding: 20px 20px 0px 0px; }
вот что будет:
если добавите clear: left
к изображениям, они разместятся вертикально, а не горизонтально:
Это перевод части справочника CSS.
Продолжаем осваивать элементы CSS:
- ТОП-6 рецептов на чистом HTML и CSS без использования JS
- 8 простых, но полезных CSS-эффектов для вашего сайта
- My heart will beat on! Сердце на CSS для неисправимых романтиков
Стилевые правила записываются в собственном формате, отличном от HTML. Основным понятием выступает селектор — это шаблон, который используется для выбора одного или нескольких элементов HTML и применения к ним параметров форматирования. Общий способ записи имеет следующий вид.
Вначале указывается имя селектора, например, div, это означает, что все стилевые параметры будут применяться ко всем элементам <div> в HTML-документе. Затем пишутся фигурные скобки, внутри которых идёт стилевое свойство, а его значение указывается после двоеточия. Стилевые свойства разделяются между собой точкой с запятой, в конце этот символ можно опустить.
CSS не чувствителен к регистру, переносу строк, пробелам и символам табуляции, поэтому форма записи зависит от желания разработчика. Так, в примере 1 показаны две разновидности оформления селекторов и их правил.
Пример 1. Использование стилей
<!DOCTYPE html>
<html>
<head>
<meta charset=»utf-8″>
<title>Заголовки</title>
<style>
h1 {color:#a6780a;font-weight:normal;}
h2 {
color: olive;
border-bottom: 2px solid black;
}
</style>
</head>
<body>
<h1>Заголовок 1</h1>
<h2>Заголовок 2</h2>
</body>
</html>
В данном примере свойства селектора h1 записаны в одну строку без пробелов, а для селектора h2 каждое свойство располагается на отдельной строке. Во втором случае проще отыскивать нужные свойства и править их по необходимости, но при этом незначительно возрастает объём данных за счёт активного использования пробелов и переносов строк. Обычно при разработке сайта используют наиболее удобную и наглядную форму записи, а уже перед публикацией сайта из стилевого файла для сокращения его объёма удаляются все пробелы и переносы строк.
Правила применения стилей
Далее приведены некоторые правила, которые необходимо знать при описании стиля.
Форма записи
Для селектора допускается добавлять каждое стилевое свойство и его значение по отдельности, как это показано в примере 2.
Пример 2. Расширенная форма записи
td { background: olive; }
td { color: white; }
td { border: 1px solid black; }
Однако такая запись не очень удобна. Приходится повторять несколько раз один и тот же селектор, да и легко запутаться в их количестве. Поэтому практичнее писать все свойства для каждого селектора вместе. Указанный набор записей в таком случае получит следующий вид (пример 3).
Пример 3. Компактная форма записи
td {
background: olive; /* Оливковый цвет фона */
color: white; /* Белый цвет текста */
border: 1px solid black; /* Чёрная рамка */
}
Эта форма записи более наглядная и удобная в использовании.
Имеет приоритет значение, указанное в коде ниже
Если для селектора вначале задаётся свойство с одним значением, а затем то же свойство, но уже с другим значением, то применяться будет то значение, которое в коде CSS установлено ниже (пример 4).
Пример 4. Разные значения у одного свойства
p { color: green; /* Зелёный цвет текста */ }
p { color: red; /* Красный цвет текста */ }
В данном примере для селектора p цвет текста вначале установлен зелёным, а затем красным. Поскольку значение red расположено ниже, то оно в итоге и будет применяться к тексту.
На деле такой записи лучше вообще избегать и удалять повторяющиеся значения. Но подобное может произойти случайно, к примеру, в случае подключения разных стилевых файлов, в которых содержатся одинаковые селекторы.
Значения
У каждого свойства может быть только соответствующее его целям значение. Например, для color, который устанавливает цвет текста, в качестве значений недопустимо использовать числа.
Комментарии
Комментарии нужны, чтобы делать пояснения по поводу использования того или иного стилевого свойства, выделять разделы или писать свои заметки. Комментарии позволяют легко вспоминать логику и структуру селекторов, а также повышают разборчивость кода. Комментарии обычно применяют в отладочных или учебных целях, а при публикации сайта их стирают.
Чтобы пометить, что текст является комментарием, применяют следующую конструкцию /* … */ (пример 5).
Пример 5. Комментарии в CSS-файле
/*
Стиль для сайта webref.ru
Сделан для ознакомительных целей
*/
div {
width: 200px; /* Ширина блока в пикселях */
background: #f0f0f0; /* Серый цвет фона */
border: 1px solid olive; /* Оливковая рамка */
}
Как следует из данного примера, комментарии можно добавлять в любое место CSS-документа, а также писать текст комментария в несколько строк. Вложенные комментарии, когда один комментарий располагается внутри другого, недопустимы.
Перейти к заданиям
Последнее изменение: 01.06.2020
Особенности применения и основные возможности современного CSS. Принципы каскадных таблиц стилей и типы селекторов. Понятие блочной и альтернативной моделей, описание их свойств.
Урок 4. Современный CSS: Основные понятия, селекторы, блочная модель
Особенности применения и основные возможности современного CSS. Принципы каскадных таблиц стилей и типы селекторов. Понятие блочной и альтернативной моделей, описание их свойств.
Оглавление
Теоретический блок
1. Каскадные таблицы стилей: определение и возможности
2. Основные категории CSS
3. Способы подключения стилей
- Встроенные стили (inline styles)
- Внутренние стили (internal styles)
- Внешние, подключаемые стили (external styles)
4. Виды селекторов в CSS
- Глобальный селектор
- Селектор по элементу
- Селектор по классу
- Селектор по идентификатору
- Селектор по атрибуту
- Селектор по псевдоклассу
- Селектор по псевдоэлементу
- Групповые селекторы
- Комбинированные селекторы
5. Принципы работы CSS
- Каскадность (Cascade)
- Специфичность (Specificity)
- Наследование (Inheritance)
6. Блочные (Block) и строчные (inline) элементы
7. Стандартная и альтернативная блочные модели (Box models)
- Стандартная модель
- Альтернативная модель
Перейти
Практический блок
1. Вопросы
2. Задания
3. Ответы
Перейти
ТЕОРЕТИЧЕСКИЙ БЛОК
Каскадные таблицы стилей: определение и возможности
Стилизация элементов веб-страницы и задание внешнего вида документа достигается при помощи языка CSS (Cascading Style Sheets, Каскадные таблицы стилей). Он позволяет применять все современные возможности браузеров для «отрисовки» посещаемых сайтов.
“
Каскадные таблицы стилей – инструмент описания внешнего вида страниц web-ресурса, использующих в качестве конструктора язык разметки HTML или XML.
Сочетание CSS и HTML – неотъемлемая часть веб-разработки. Таблицы стилей как бы дополняют язык разметки, опосредованно расширяют его функционал.
Недостатки сайтов на «чистом» HTML:
- Статичность (страницы не меняются, отсутствует динамика и анимации);
- Непредсказуемость поведения в разных браузерах (хоть теги и понимаются практически всеми ими, тем не менее может визуально модифицироваться их отображение у пользователя с учетом его настроек);
- Минималистичность, непривлекательность – сам по себе HTML практически не позволяет как-то настраивать внешний вид элементов (следовательно, приятных и эргономичных сайтов на нем не построишь).
CSS первой версии появились в далеком 1996 г и содержали не такой большой набор правил, как сегодня. Правда, уже тогда были заложены основные категории и понятия: селекторы, блочно-строчное форматирование, псевдоэлементы и т.п.
Вторая версия каскадных таблиц стилей пришла в 1998 г и принесла с собой комбинаторы, табличную модель, голосовые стили.
Сегодня мы говорим о CSS3, что функционирует с 2007 г. Он постоянно развивается и дополняется, хоть и не меняет версию. К сегодняшнему моменту CSS поддерживает практически все «фишки» современных браузеров и устройств и способен удовлетворить потребности разных групп пользователей, вплоть до тех, у кого имеются ограниченные возможности контакта с ПК.
Для наглядности понимания стека web-разработки HTML-CSS-JavaScript приведем аналогию. Представьте строящееся здание:
1. HTML – это каркас строения, крыша, полы, стены.
2. CSS – элементы декоративного свойства, украшательства (от обоев, линолеума до мебели и картин в помещении). Они созданы специально для человека: для удобства, эстетичности. Ведь ПК все равно видит лишь байты.
3. JavaScript – функциональные элементы (работа с освещением, водопроводом, регулирование температуры и т.п.).
Основные категории CSS
Для начала работы с CSS на страницах сайта необходимо разобраться с терминологией. Структура любого элемента каскадных таблиц представлена ниже.
Как видно из картинки, задание CSS-свойств для HTML-элементов подразумевает объявление селектора, а внутри фигурных скобок через точку с запятой перечисляются свойства и их значения.
Охарактеризуем каждую категорию:
1. Ruleset (набор правил) – весь блок конкретного селектора со всеми изменяемыми параметрами. В нашем случае в качестве такового выступает тег <p> и его свойства: цвет и внутренние отступы.
2. Selector (селектор) – модифицируемая категория (тег <p>). В качестве селектора могут выступать не только теги, но и классы, идентификаторы, псевдоэлементы и псевдоклассы, конкретные атрибуты. Селекторы бывают сложными (с учетом наследования).
3. Declaration (декларация, объявление) – конкретная пара свойство: значение. Количество таких пар не ограничено. Пара обязательно должна заканчиваться точкой с запятой.
4. Property (свойство) – атрибут элемента, для которого мы планируем задать определенное значение. На рисунке в качестве таковых представлены цвет текста (color), внутренние отступы от границы блока со всех сторон (padding).
5. Value (значение) – конкретная величина атрибута. В примере цвет текста сделан зеленым, а отступы – 15 пикселей. Варианты значений свойств определяются документацией.
При нарушении синтаксиса набора правил в любом месте никаких ошибок на странице видно не будет, но сами правила не будут применены к выбранному селектору. Другими словами, если что-то не работает как задумано, требуется проверить синтаксис, валидность свойств и селекторов, допустимость значений.
Способы подключения стилей
Чтобы каскадные таблицы стилей отображались на странице необходимо не только правильно их задать, но и подключить. Для этого имеется 3 варианта.
1. Встроенные стили (inline styles)
Каждому тегу в HTML-документе можно задать атрибут style, внутри которого описываются свойства и значения.
<article style="color: darkgoldenrod; font-size: xx-large;">Параграф текста</article>
На практике принято задавать значения атрибутов внутри двойных кавычек (хотя можно использовать и одинарные). В представленном примере для тега <article> определен темно-золотистый цвет шрифта и увеличенный размер.
Такое применение стилизации элементов не рекомендуется, так как теряется смысл CSS, но в некоторых случаях допустимо (для получения максимального приоритета стиля).
2. Внутренние стили (internal styles)
Используются внутри HTML-страницы без вынесения в отдельный файл. Оправдано в случае небольшого количества модифицируемых элементов на компактных страничках. Определяются в теге <style>.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Практика CSS</title>
<link rel="stylesheet" href="style.css">
<style>
article {
color: darkgoldenrod;
font-size: xx-large;
}
</style>
</head>
<body>
<article>Параграф текста</article>
</body>
</html>
Данный способ задания стилей декларируется, обычно, в теге <head>.
3. Внешние, подключаемые стили (external styles)
Наиболее часто встречаемый способ задания стилей на страницах. Для этого создается один или несколько файлов с расширением .css, путь к которым указывается в теге <link>, расположенном в заголовочной части HTML-документа.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Практика CSS</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<article>Параграф текста</article>
</body>
</html>
/* Файл style.css */
article {
color: darkgoldenrod;
font-size: xx-large;
}
К документу HTML мы подключили внешний файл с таблицами стилей style.css. К слову, у тега <link> атрибут type в данном случае можно не указывать, так как CSS на сегодня единственный язык таблиц стилей, применяемый в сети.
Так какой вариант лучше?
Три приведенных способа дают одинаковый результат. В современной web-разработке, когда стилизуемых элементов может быть огромное количество, наиболее оптимальным является третий способ. Для этого обычно в папке проекта создается директория css, внутри которой размещаются таблицы стилей (для больших проектов характерна их множественность).
В дальнейших примерах будет использоваться HTML-страница index.html, рядом с которой расположится папка css, где создадим текстовый документ style.css. Это хорошая практика.
Структура тестового проекта
Базовая структура корневого HTML-файла следующая:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Практика CSS</title>
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
</body>
</html>
В последующем она приводиться не будет. Внутри тега <body> при необходимости разместятся другие элементы (т.е. в примерах мы покажем лишь содержимое <body>).
Виды селекторов в CSS
Задание свойств элементам страницы через каскадные таблицы стилей предполагает первоначальную выборку селекторов. Вариантов осуществления такой операции не мало:
1. Глобальный селектор
2. Селектор по элементу
3. Селектор по классу
4. Селектор по идентификатору
5. Селектор по атрибуту
6. Селектор по псевдоклассу
7. Селектор по псевдоэлементу
8. Групповые селекторы
9. Комбинированные селекторы
- 9.1. Селектор потомков
- 9.2. Селектор дочерних элементов
- 9.3. Селектор «первого соседа»
- 9.4. Селектор «всех соседей»
Рассмотрим наиболее типичные, с которыми часто встречаются на практике.
4.1. Глобальный селектор
Объявляется звездочкой и подразумевает воздействие на все элементы страницы, где данное свойство имеется.
<h1>Главная страница сайта</h1>
<article>Как работать с CSS</article>
* {
background-color: lightsalmon;
font-size: 30px;
}
Каждому тегу на странице сайта будет присвоен цвет фона светло-розовый, а также размер шрифта в 30 пикселей.
Данный селектор используется не часто, но иногда требуется для сброса всех настроек (так как браузеры зачастую сами задают отступы у блочных тегов, например, а мы хотим их отключить). Позволяет добиться максимальной идентичности внешнего вида нашего ресурса на разных браузерах и устройствах.
4.2. Селектор по элементу
В качестве селектора выступает конкретный тег HTML. Новые настройки распространятся на все эти объекты, встречаемые в коде, независимо от вложенности.
<h1>Главная страница сайта</h1>
<q>Практика - основа мастерства</q>
<p>
<q>Делай - и научишься</q>
</p>
q {
color: maroon;
font-size: 15px;
}
Все цитаты в документе приобрели бордовый оттенок и отображаются 15-ым шрифтом.
4.3. Селектор по классу
Каждому HTML-элементу можно присвоить класс, задав ему некоторое имя. Это позволяет группировать теги и выделять их особым образом в документе. В СSS к классу обращаются с селектором, начинающимся с точки.
<h1 class="blue-wave">Главная страница сайта</h1>
<q class="blue-wave">Практика - основа мастерства</q>
<p>
<q>Делай - и научишься</q>
</p>
.blue-wave {
text-decoration-style: wavy;
text-decoration-color: blue;
text-decoration-line: overline;
}
Нами создан класс blue-wave, который задан для заголовка <h1> и первой цитаты. Всем элементам этого класса присвоено верхнее подчеркивание синего цвета в виде волнистой линии.
4.4. Селектор по идентификатору
ID дает возможность уникализировать конкретный элемент документа. Идентификатор определенного имени может присутствовать на странице в единственном экземпляре (в отличие от имени класса). Зачастую применяется при обработке тегов и их содержимого через JavaScript.
<h1 id="red-dots">Главная страница сайта</h1>
<q class="blue-wave">Практика - основа мастерства</q>
<p>
<q>Делай - и научишься</q>
</p>
.blue-wave {
text-decoration-style: wavy;
text-decoration-color: blue;
text-decoration-line: overline;
}
#red-dots {
text-decoration-style: dotted;
text-decoration-color: red;
text-decoration-line: underline;
}
Селектор идентификатора начинается со знака решетки. Теперь заголовок первого уровня подчеркнут снизу красной линией в виде точек.
4.5. Селектор по атрибуту
Выбрать элемент документа можно и по наличию у него определенного свойства и значения. Для этого в квадратных скобках указывается атрибут с или без значения.
<a href="https://yandex.ru/">Яндекс</a>
<br>
<a href="https://www.google.com/">Гугл</a>
a[href="https://yandex.ru/"] {
font-size: 40px;
text-decoration-line: line-through;
}
Ссылка, ведущая на Яндекс, существенно увеличилась в размере и стала перечеркнутой, тогда как с Google ничего не произошло.
4.6. Селектор по псевдоклассу
Псевдокласс определяет особое состояние HTML-элемента. Это позволяет стилизовать его не только на основании положения в DOM-дереве, но и с учетом ряда внешних факторов (история посещения, положение курсора мыши и др.). На сегодня их насчитывается около 40 штук. Применимы не ко всем элементам. Для правильной работы следует ознакомиться с документацией, так как возможны непредвиденные эффекты.
Задаются через двоеточие:
<a href="https://yandex.ru/">Яндекс</a>
<br>
<a href="https://www.google.com/">Гугл</a>
a:link {
font-size: 15px;
color: tomato;
}
a:visited {
font-size: 20px;
color: saddlebrown;
}
a:hover {
font-size: 25px;
color: seagreen;
}
a:active {
font-size: 30px;
color: violet;
}
Изначально все ссылки имеют небольшой размер шрифта и красноватый оттенок. Посещенные становятся коричневыми. При наведении мыши получаем зеленый цвет, а активная ссылка (при нажатии и удержании левой кнопки мыши) приобретает фиолетовый оттенок.
Страница Web-браузера до перехода по ссылкам
Страница Web-браузера после перехода по ссылкам (a:visited)
Это важно
Согласно документации, приведенный порядок объявления псевдоэлементов (a:link, a:visited, a:hover, a:active) является обязательным, в противном случае они не будут корректно работать.
4.7. Селектор по псевдоэлементу
Псевдоэлементы стилизуют некоторую часть элемента. Задаются через два двоеточия. Их пока не так много, тем не менее они довольно часто встречаются в коде верстальщиков.
<h1>Изучаем псевдоэлементы</h1>
<section>
При помощи ::first-line мы преобразуем первую строку данного тега к верхнему регистру.
<br>
Остальные строки при этом остаются неизменными, такими, какими мы их задали изначально.
</section>
section::first-line {
text-transform: uppercase;
}
Как видим, первая строка полностью переведена в верхний регистр.
4.8. Групповые селекторы
При перечислении любых селекторов через запятую им можно задать одинаковые свойства.
<h1>Фанаты зеленого цвета</h1>
<article>
<header>
Говорят, зеленый цвет успокаивает глаза.
</header>
<section>
Дизайнеры считают, что применение зеленого цвета способствует отдыху глаз.
Но это не доказано учеными, поэтому поверим на слово.
</section>
<footer>
Исследование планируется к проведению в Швеции, тогда и проверим.
</footer>
</article>
h1, header, section {
color: seagreen;
}
Для трех тегов (h1, header, section) мы задали цвет шрифта светло-зеленого оттенка, что не привело к дублированию кода.
4.9. Комбинированные селекторы
Использование комбинаторов позволяет выбирать элементы на основании отношения между ними. Выделяют 4 типа комбинаторов:
4.9.1 Селектор потомков
Задается пробелом. Все элементы, расположенные внутри родительского, независимо от уровня вложенности, будут задействованы.
<h1>Комбинаторы</h1>
<p>Что это и зачем</p>
<article>
<header>
<p>Первый параграф</p>
<p>Второй параграф</p>
</header>
<section>
<p>Третий параграф</p>
<p>Четвертый параграф</p>
</section>
<footer>
<p>Пятый параграф</p>
<p>Шестой параграф</p>
</footer>
</article>
article p {
font-size: 25px;
background-color: bisque;
}
Внутри тега <article> имеются теги <p>. Несмотря на то, что они не дочерние элементы, селектор воздействовал на них в соответствии с правилом.
4.9.2 Селектор дочерних элементов
Выбирает только первых потомков, игнорируя остальных на более глубоких уровнях вложенности. Определяется знаком >.
<body>
<h1>Комбинаторы</h1>
<p>Что это и зачем</p>
<article>
<header>
<p>Первый параграф</p>
<p>Второй параграф</p>
</header>
<section>
<p>Третий параграф</p>
<p>Четвертый параграф</p>
</section>
<footer>
<p>Пятый параграф</p>
<p>Шестой параграф</p>
</footer>
</article>
<p>Конец</p>
</body>
body > p {
font-size: 25px;
background-color: bisque;
}
Воздействие селектора наблюдается только на те параграфы, которые непосредственно наследуются от <body> (с текстом Что это и зачем и Конец).
4.9.3 Селектор «первого соседа»
Когда 2 элемента на странице идут друг за другом на одном уровне DOM-дерева, можно применить комбинатор «первого соседа». Для этого используется знак +.
<h1>Комбинаторы</h1>
<p>Что это и зачем</p>
<article>
<header>
<p>Первый параграф</p>
<p>Второй параграф</p>
</header>
<section>
<p>Третий параграф</p>
<p>Четвертый параграф</p>
</section>
<footer>
<p>Пятый параграф</p>
<p>Шестой параграф</p>
</footer>
</article>
<p>Конец</p>
h1 + p {
font-size: 25px;
background-color: burlywood;
}
Цвет и шрифт поменялся только у первого параграфа, идущего после тега <h1> и находящегося с ним на одном уровне иерархии.
4.9.4 Селектор «всех соседей»
Выбираются все идущие далее соседи (т.е. находящиеся на одном уровне иерархии элементы). Задаются символом ~.
<h1>Комбинаторы</h1>
<p>Что это и зачем</p>
<article>
<q>Какая-то цитата</q>
<p>Первый параграф</p>
<p>Второй параграф</p>
</article>
<p>Конец</p>
article ~ p, q ~ p {
font-size: 25px;
background-color: burlywood;
}
Как видно, изменены только параграфы с текстом Первый параграф, Второй параграф и Конец как соседние и идущие после начальных (q и article соответственно).
Подытожим
Применяя разные техники комбинирования селекторов, мы можем задавать уникальные свойства для разных частей веб-страницы при минимизации объемов кода и исключении дублирования.
Принципы работы CSS
При работе с каскадными таблицами стилей возникают ситуации, когда нам не понятно, какое же свойство будет в итоге у того или иного элемента. Например, мы задали размер текста для тега <body>, а потом и для тега <p>. Возникает вопрос: какого же размера будет содержимое параграфа? Таких ситуаций при формировании сложных таблиц стилей возможно громадное множество.
Для понимания приоритетов наследования стилей определены принципы работы CSS.
5.1. Каскадность (Cascade)
Каскадность подразумевает возможность применения стилей из разных источников к одному и тому же объекту. Браузеру необходимо разобраться с тем, каким образом отображать элемент.
Для этого выстраивается очередь приоритетов в следующем порядке (от самого низкого до максимально значимого):
- Таблицы стилей браузера (у многих просмотрщиков для разных элементов определены стили по умолчанию – шрифты, отступы, границы, размеры);
- Таблицы стилей пользователя (посетитель сайта может заранее настроить отображение тегов у себя в браузере. Если они не переопределены разработчиками, то будут использованы);
- Таблицы стилей разработчика (автор сайта задает настройки элементам, которые по приоритету выше, чем два предыдущих типа. Это рассчитано на максимальную схожесть внешнего вида ресурса у пользователей);
- Стили браузера !important (значение !important у любого свойства имеет повышенный приоритет);
- Стили пользователя !important (пользователь также может принудительно вызвать определенный стиль, установив значение !important);
- Стили разработчика !important (максимально высокий приоритет).
Приоритетность применения стилей
Значения !important устанавливать не рекомендуется, но в некоторых случаях могут использоваться для уверенности срабатывания стилизации.
Как видим, стили разработчика выше по приоритету, чем все остальные. Если они установлены, то будут отображаться. В противном случае «решение» принимает браузер или пользовательские настройки посетителя.
<h1>Основная страница</h1>
<article>
<p>Важное содержимое статьи</p>
</article>
<footer>Сайт разработан специалистами Smartiqa Group</footer>
p {
font-size: 24px;
color: chocolate;
background-color: lightblue;
}
Итак, для параграфа мы изменили фон, цвет и размер шрифта. Тем не менее, у него есть и другие свойства, унаследованные от браузера. Их можно посмотреть в консоли разработчика (Клавиша F12 —> Стили):
Пример – Консоль разработчика
p {
display: block;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0px;
margin-inline-end: 0px;
}
Инструменты разработчика — Стили
Если одно из них поменять, то сработает приоритет стиля разработчика.
p {
font-size: 24px;
color: chocolate;
background-color: lightblue;
margin-inline-start: 25px;
}
Пример – Консоль разработчика
p {
display: block;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0px;
margin-inline-end: 0px;
}
Теперь абзац получил отступ слева на 25 пикселей на первой строке.
Инструменты разработчика — Стили
5.2. Специфичность (Specificity)
Отвечает за приоритет применения стилей к элементам в зависимости от типа селектора.
Специфичность подразумевает задание весов конкретным правилам. Более высокая его величина определяет итоговое значение отображаемого свойства.
Цепочка приоритетов выглядит так (в порядке увеличения значимости):
- Селекторы элементов и псевдоэлементов (выбирается конкретный тег или его часть);
- Селекторы классов, атрибутов и псевдоклассов (выбор на основании класса, специфичного атрибута или состояния класса);
- Селекторы идентификаторов (так как задаются в единственном экземпляре на странице, то имеют максимальный вес).
Приоритетность применения стилей к web-элементам
Комбинаторы, глобальный селектор (звездочка), псевдокласс отрицания :not() – не оказывают влияния на специфичность. Для задания максимального приоритета на любом уровне используют !important, что, опять же, не рекомендуется (за редкими исключениями).
Важно понимать, что независимо от порядка объявления селекторов в файле стилей, их приоритет не меняется (за исключением равноправных).
<h1>Основная страница</h1>
<article id="main-content">
<p class="blue-paragraph">Важное содержимое статьи</p>
</article>
p {
background-color: cyan;
}
#main-content p{
background-color: yellow;
}
article p{
background-color: red;
}
.blue-paragraph {
background-color: darkolivegreen;
}
Так как идентификатор в данном случае максимально приоритетен, то цвет фона внутри параграфа станет желтым.
Если же любому другому селектору присвоить !important, то сработает он.
p {
background-color:cyan;
}
#main-content p{
background-color:darkolivegreen;
}
article p{
background-color:red !important;
}
.blue-paragraph {
background-color:yellow;
}
Теперь цвет изменился на красный.
5.3. Наследование (Inheritance)
Еще один способ определения конечных свойств элемента – на основании наследования. Как известно, DOM-дерево представлено родителями и потомками, поэтому при вычислении свойств дочерних элементов используются параметры предков, если они не указаны для потомков.
Не все CSS свойства по умолчанию наследуются, о чем можно узнать из документации. К таковым, например, относят границы у элементов, их цвет и толщина, отступы. Тем не менее, если необходимо, можно принудительно задать наследование через значение inherit.
<h1>Основная страница</h1>
<article>
<p>Параграф первый</p>
<p>Параграф второй</p>
</article>
article {
border: tomato 10px solid;
}
Вокруг тега <article> мы построили сплошную рамку толщиной 10 пикселей красного цвета. Теги параграфов, находящиеся внутри статьи, не получили это свойство, так как оно по умолчанию ненаследуемое.
Мы можем «заставить» их наследоваться.
article {
border: tomato 10px solid;
}
article p {
border: inherit;
}
Теперь параграфы, находящиеся внутри тега <article>, имеют те же свойства границ.
Подытожим
Таким образом, при формировании селекторов в CSS необходимо понимать принципы их наследования, специфичности, каскадности. Это позволит избежать ошибок при стилизации объектов и исключить излишние строки кода (когда не понятно, почему не работает то или иное свойство, «ленивые разработчики» балуются использованием !important).
Блочные (Block) и строчные (inline) элементы
Перейдем к особенностям отображения элементов на странице. Каждый верстальщик рассматривает структуру страницы как набор неких коробок, блоков. Такое видение сайта позволяет понять специфику отображения объектов. Любой макет будущего ресурса представляет собой набор прямоугольников с определенным контентом. Если это усвоить, то верстка макета не составит никаких проблем.
Если упрощенно, то при разработке все элементы сайта условно делят на 2 типа: блочные и строчные (как говорилось в уроках по HTML). Опишем эти «коробки».
1. Блочная (block) структура имеет особенности:
- Каждый элемент такого типа начинается с новой строки (например, теги <div> или <article>. Другими словами, независимо от того, насколько велико содержимое объектов, каждый из них начнется с новой строчки);
- Данная коробка стремится к полному заполнению доступного ей пространства (расширение на всю область страницы или родительского элемента);
- Ей можно задавать ширину и высоту (т.е. свойства width и height);
- Задание параметров отступов (внутренних или внешних) или границ отодвинут другие объекты от текущего.
2. Строчная (inline) структура характеризуется:
- Перенос на новую строчку не произойдет, если остается доступное пространство на текущей;
- Задание ширины и высоты не имеет смысла, так как эти параметры связаны только лишь с контентом и его объемом (другими словами, если строчному элементу задать ширину в 500 пикселей, то нет никакой гарантии, что это произойдет, особенно в случае, если вы внутрь того же тега <strong> поместили только число 2021);
- Применение отступов и границ оправдано, но они не отодвинут другие объекты, а лишь скажутся на содержимом самой строки;
Блочные и строчные web-элементы
Определение строчности или блочности элемента связано, в первую очередь, со спецификой используемого тега (о чем сказано в документации). Благодаря CSS имеется возможность изменить тип объекта на тот, который нам подходит исходя из целей. Проще говоря, блочный элемент легко превратить в строчный, и наоборот. Для этого применяется свойство display.
<h1>Основная страница</h1>
<h2>Часть 1: Мои сайты для поиска</h2>
<a href="https://www.yahoo.com/">Главная страница Yahoo</a>
<a href="https://mail.ru/">Главная страница mail.ru</a>
Если не использовать стили, то отображение элементов на странице будет носить дефолтный характер: <h1> и <h2> – это блоки, а ссылки – строки.
Страница web-браузера. Дефолтное поведение элементов.
<h1>Основная страница</h1>
<h2>Часть 1: Мои сайты для поиска</h2>
<a href="https://www.yahoo.com/">Главная страница Yahoo</a>
<a href="https://mail.ru/">Главная страница mail.ru</a>
h1, h2 {
display: inline;
}
a {
display: block;
}
Проведенные манипуляции превратили заголовки в inline-элементы (они теперь отрисовываются на одной строке), а ссылки – в блоки.
Страница web-браузера. Измененное поведение элементов.
Также необходимо отметить, что помимо блочных и строчных элементов возможно присутствие и других типов: флексы (flex), сетки (grid), таблицы (table), строчные блоки (inline-block) и другие. Более того, прямые наследники таких элементов могут приобрести особое поведение (например, все дочерние объекты flex-типа станут гибкими и будут вести себя в соответствии с правилами. О них мы поговорим в одноименном разделе).
Стандартная и альтернативная блочные модели
(Box models)
Как упоминалось выше, все объекты страницы ведут себя либо как блок, либо как строка (в общем случае). Так или иначе, они характеризуются набором параметров, о которых не следует забывать при формировании макета страницы.
Предположим, нам требуется создать блок <article> размером 450 на 250 пикселей с отступами и границами. Эти дополнительные свойства по умолчанию будут учитываться, что может расширить реальные размеры коробки. С другой стороны, CSS не запрещает задать точные размеры элемента с включением всех его свойств.
Вначале посмотрим на все свойства блока с учетом параметров размеров (показаны на рисунке ниже).
Области блочного элемента
Вычисление размера блока осуществляется по атрибутам:
- Параметры контента (свойства width и height);
- Внутренние отступы (свойство padding);
- Граница, рамка (свойство border);
- Внешние отступы (свойство margin).
Общий размер элемента, в итоге, будет определяться на основании стандартной или альтернативной блочной модели.
7.1. Стандартная модель
Вычисляет размер блока как сумму всех означенных выше параметров. Так, если задать ширину блока, то к ней прибавится размер внутренних и внешних отступов по конкретной оси, а также величина границы.
<h1>Основы CSS - стандартная модель</h1>
h1 {
width: 650px;
height: 300px;
padding: 10px;
margin: 20px;
border: 5px solid black;
}
На что обратить внимание?
1. Свойство padding при передаче одного значения определяет внутренние отступы от содержимого по всем четырем направлениям (внизу, вверху, слева, справа).
2. Свойство border характеризует толщину рамки, ее вид (в нашем случае – сплошная линия), цвет.
3. Свойство margin задает отступы от других блоков страницы по тем же четырем направлениям.
4. На основании стандартной модели итоговый размер блока будет не 650 на 300 пикселей, а следующим:
– ширина: 650 + 10 +10 + 5 + 5 + 20 + 20 = 720 px;
– высота: 300 + 10 +10 + 5 + 5 + 20 + 20 = 370 px.
В ряде случае это неудобно, так как заказчик требует размер блока с учетом всех отступов и границ.
7.2. Альтернативная модель
В такой ситуации удобна альтернативная блочная модель, которая определяет размер коробки с учетом дополнительных свойств. Для этого задается box-sizing: border-box;.
<h1>Основы CSS - стандартная модель</h1>
h1 {
width: 650px;
height: 300px;
padding: 10px;
margin: 20px;
border: 5px solid black;
box-sizing: border-box;
}
В результате параметры заголовка будут включать в себя внутренние отступы и границы, но не внешние отступы. Их включение в CSS не предусмотрено, но даже при таких обстоятельствах вычислять размеры блока значительно проще:
– ширина: 650 + 20 + 20 = 690 px;
– высота: 300 + 20 + 20 = 340 px.
Блочная модель CSS: Стандартная и альтернативная модели
Если же свойство margin строго не определено, то конечные размеры элемента можно считать такими, какими они были определены изначально на основании ширины и высоты.
При работе со строчными элементами часть свойств не будет работать. В частности, ширина и высота не возымеют никакого эффекта. Отступы и границы отображаются, но с некоторыми недочетами: они будут перекрывать содержимое других объектов.
Самое простое решение проблемы – inline-block. Мы показываем содержимое элемента как блок, но он не будет занимать всю ширину родителя. Получается микс строки и блока. В этом случае никаких проблем с отображением объекта в соответствии с нашей задумкой не будет.
<strong>Немало в мире умных фраз</strong>
<q>Не думай - размышляй</q>
<i>Но есть и не совсем умные</i>
q {
width: 450px;
height: 200px;
padding: 20px;
margin: 10px;
border: 4px solid black;
display: inline-block;
}
Элемент <q> имеет высоту и ширину, отступы внутренние и внешние, а также границу в 4 пикселя. Хоть он и не занимает всю ширину родителя (тега <body>), но вполне соответствует заданным параметрам.
Элемент <q> со свойством display: inline-block;
Если не использовать декларацию display: inline-block;, то поведение текста с цитатой будет не столь очевидным, а параметры ширины и высоты полностью проигнорируются.
Элемент <q> БЕЗ свойства display: inline-block;
Для более детального ознакомления с CSS рекомендуется изучать официальную документацию (с сайта World Wide Web консорциума). Детальное описание свойств и их возможных значений, а также примеры применения доступны на сайте Mozilla (в том числе и на русском языке). Ссылки приведены ниже.
Дополнительные ресурсы по теме CSS
1. Спецификации и их описание: "https://www.w3.org/Style/CSS/specs.en.html#translations"
2. Руководство от Mozilla: "https://developer.mozilla.org/ru/docs/Web/CSS/Reference"
ПОДЫТОЖИМ
Подведем промежуточные итоги. Каскадные таблицы стилей существенно упрощают модифицирование HTML-элементов, позволяя делать сайты современными, эргономичными. Чтобы ресурс не выглядел как сплошной набор текстового полотна, CSS дает возможность выделять требуемые блоки, делать отступы, менять размеры шрифта и блоков, применять цветовое оформление.
ПРАКТИЧЕСКИЙ БЛОК
Вопросы
Псевдоэлемент ::first-letter применяется для выделения первого буквенного или числового символа блочного элемента (в том числе иероглифов). Нужно помнить, что любой другой символ также подвергнется модификации, но не будет учитываться в качестве первого (как и все специальные знаки после первого валидного знака).
Пример – HTML
—
<p>Просто абзац какого-то текста</p>
<p>)1…… Модифицируется и скобка, и цифра 1, да еще и все точки!</p>
Пример – CSS
—
p::first-letter {
color: red;
font-size: 40px;
}
В первом абзаце красным цветом и увеличенным шрифтом будет наделена первая буква – П, а во втором, помимо цифры 1, изменится скобка и все последующие точки до буквы М.
Псевдоэлементы ::after и ::before чаще всего позволяют добавить косметические украшательства до и после родительского элемента.
Пример – HTML
—
<a href=»https://yandex.ru/»> Яндекс </a>
Пример – CSS
—
a::after {
content: «🧡»;
}
a::before {
content: «💚»;
}
Здесь мы выделили ссылку разноцветными сердечками.
Согласно приоритетам в наследовании свойств CSS выстраивается следующая последовательность (по мере роста значимости):
– 60 пикселей у тега <p>;
– 22 пикселя у класса txt;
– 10 пикселей у идентификатора txt;
– задание внутреннего стиля с помощью атрибута style – 42 пикселя.
Получается, итоговый размер шрифта абзаца составит 42 px, так как у инлайн-стиля максимальный приоритет.
Задание
Задание
Создайте 3 ссылки (на любые поисковые системы), каждая из которых будет начинаться с новой строки, иметь сплошную зеленую границу толщиной 7 пикселей и суммарный размер 300 на 200 пикселей. Вертикальный отступ между ссылками составит 10 пикселей.
Решение
Наша задача – минимизация строк кода. Поэтому применять всякие разрывы строк (при помощи тега <br>) будет не логичным.
Оптимальное решение – присвоение всем ссылкам режима отображения block. Также следует учесть, что внешние отступы между объектами суммируются (так как у одного объекта есть, например отступ снизу, а у следующего за ним — отступ сверху).
<a href="https://www.yahoo.com/">Yahoo</a>
<a href="https://yandex.ru/">Яндекс</a>
<a href="https://www.google.com/">Google</a>
a {
width: 300px;
height: 200px;
margin: 5px;
border: 7px solid green;
display: block;
box-sizing: border-box;
}
Так как ссылки – строчные элементы, их следует преобразовать в блочные. А чтобы не высчитывать из ширины и высоты размеры границы, удобно воспользоваться декларацией box-sizing: border-box;.
С учетом суммирования внешних отступов нужно задать их величину в размере 5 пикселей (что приведет к нужным десяти, если просуммировать margin ссылки и ее соседа).
Как вам материал?