Веб-разработка
June 25, 2022

Сборник тонкостей CSS — селекторы, фоны и рамки — Тренажёр HTML Academy

Перескочим на «продвинутый» уровень тренажёров. Под «тонкостями» в тренажёрах имеются ввиду несколько дополнительных частей к уже пройденным — более сложные селекторы, специфичные свойства рамок, фонов и текста. А еще изучим построение таблиц на CSS.

Перескакиваю я потому, что в среднем остался только JavaScript и еще блок про SVG. Я подумал, раз после определённого момента порядок блоков уже условный, то лучше доучить остатки CSS из продвинутого уровня, а потом уже браться за JS и остальное и потом плавно перейдём уже на курсы.

Селекторы

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

Продвинутый селектор по атрибуту

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

input[type="text"] {...} /* все input с type="text" */

У этого вида селекторов есть дополнительные механизмы поиска элементов — перед знаком равно = добавляется модификатор для поиска «подстроки», то есть части строки в значении. Модификаторов несколько и насколько я понял, все они взяты из регулярных выражений и работают аналогичным образом.

  • Начало строки [attr^="value"] — символ ^ указывает на поиск всех элементов с атрибутом attr со значением начинающегося на value. Под это подойдет, например value-1, valueone, value__top и т. д.
  • Конец строки [attr$="value"] — символ $ указывает на поиск всех элементов с атрибутом attr со значением заканчивающимся на value. Подойдёт, например, header-value, notvalue, file.value и т. д.
  • Содержит в строке [attr*="value"] — символ * указывает на поиск всех элементов с атрибутом attr со значением содержащим value в любом месте строки атрибута. Подойдет textvalue1, shop value rub, text__extd value, в общем любые совпадения.
  • Содержит слово в строке [attr~="value"] — символ ~ работает подобно *, но теперь ищет именно слово отдельно, то есть разделённое с обеих сторон либо пробелом, либо переносом строки. Подойдет shop value rub, но уже не подойдет textvalue1.
  • Содержит префикс [attr|="value"] — под префиксом имеется ввиду значение вида value- — именно с дефисом в конце, то есть частный, но распространённый случай начала строки. Также этот селектор посчитает за корректный для себя значение value — то есть одно целое слово.

Эти селекторы мне бы очень пригодились в свое время для настройки Google Tag Manager’а, когда надо было прицепиться к каким-нибудь хитро сделанным полям в каком-нибудь конструкторе.

Больше псевдоклассов

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

  • Псевдоклассы :disabled и :enabled — обращаются к элементам, чаще всего полям, с одноимённым атрибутом disabled или без него соответственно.
  • Псевдоклассы :required и :optional — обращаются к элементам, которым проставлен и, соответственно, не проставлен атрибут required — поле обязательно к заполнению.
  • Псевдоклассы :read-only и :read-write — аналогично, обращается к элементам, которым проставлен атрибут readonly и которым он не проставлен. Нам в тренажёре напоминают, что disabled визуально и функционально похож, но суть и селектор у него другой.
  • Псевдокласс :checked — обращается к элементам типа radio или checkbox, которые в данный момент выбраны.

И отдельно можно выделить псевдоклассы которые работают, можно сказать, с корректностью информации вводимой в поля. Как мы уже знаем, у некоторых типов полей, например, у email или url, есть автоматическая валидация введённых данных, а большинству остальных — область допустимых значений можно задать отдельно через атрибут pattern="".

  • Псевдокласс :valid — обращается ко всем элементам, у которых введённое значение попадает под требования.
  • Псевдокласс :invalid — напротив, обращается ко всем элементам, у которых введённое значение некорректно и не попадает под требования.

Для типов полей, где задан диапазон допустимых значений min и max — это например, number и, возможно, range, есть специальные псевдоклассы проверяющие именно попадание в диапазон.

  • Псевдокласс :in-range — обращается ко всем элементам, значение которых попадает в диапазон
  • Псевдокласс :out-of-range — выбирает все элементы, значение которых за пределами диапазона.

Именно в конце этой части нам показывают чудеса с checked и селектором ~, правда здесь мы просто скрываем блоки. Надо будет что-нибудь интересное с этим сделать.

Испытание

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

Задача не сложная, может возникнуть затык с декоративными чекбоксами и радиокнопками — это псевдоэлементы, а сами переключатели скрыты.

Рамки и фоны

Касаемо фонов — большую часть из указанного здесь мы уже видели и даже использовали. А вот с рамками, оказывается, можно делать очень интересные штуки!

Фоны

Сначала разберёмся окончательно с фонами. Первым на очереди у нас свойство отвечающее за размер фонового изображения background-size. Да, мы уже его использовали пару раз, он даже был задействован в Кексби, будь он неладен.

Это свойство принимает два типа значений — численные в px или %, которые явно обозначают ширину и высоту фонового изображения, и ключевые слова:

  • auto — значение по умолчанию для ширины и высоты.
  • contain — изображение полностью умещается в блок по большей стороне, сохраняя свои пропорции, таким образом фоновое изображение может закрывать не всё пространство блока, если их размеры и пропорции не совпадают.
  • cover — изображение полностью закрывает пространство блока, сохраняя при этом свои пропорции, части изображения не поместившиеся в блок — обрезаются.

Следующее свойство background-origin отвечает за то в каких границах будет отображаться фоновое изображение:

  • content-box — отображается только в области содержимого, то есть не отображается даже на внутренних отступах.
  • padding-box — значение по умолчанию, отображается во внутренней области бокса, исключая рамки и внешние отступы.
  • border-box — в отображение включаются рамки, даже если они непрозрачны, то есть изображение будет залезать под них.
margin-box, видимо, не завезли.

Его сосед по парте — свойство background-clip, которое отвечает за обрезку всего фона — и изображения, и цвета. Имеет абсолютно такие же значения и работает по тому же принципу, но отвечает за то в какой области будет видно, а не то на какую область растянуто. По умолчанию стоит значение border-box, то есть без обрезания фона совсем.

В этой части нам еще раз показывают принцип работы множественных фонов — в каждом специфичном фоновом свойстве порядок значений через запятую сопоставляется с порядком указанным в background-image.

Мы уже рассматривали эту особенность когда строили множественные градиенты и проставляли им background-position. Кстати, о нём. У свойства позиции фонового изображения есть возможность указать не просто числовые координаты от левого верхнего угла, а уточнить сторону от которой надо вести отсчет, например:

background-position: right 30px bottom 60px; /* справа 30px, снизу 60px */
background-position: left 50px bottom 10px; /* слева 50px, снизу 10px */

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

  • Значение round — изображение будет повторятся, но не будет обрезаться у краёв элемента. Картинка будет растягиваться, чтобы заполнить некратные размеру изображения зазоры. Это поведение ну прям о-очень похоже на работу функций repeat() и minmax() с auto-fit в гридах.
  • Значение space — изображение тоже не обрезается, но и не растягивается. Зазоры компенсируются расстоянием между изображениями, которые равномерно распределяются по пространству блока. Их поведение тоже очень похоже на уже знакомый нам space-between в выравнивании флекс-итемов во флекс-контейнере.

Рамки

Для начала отметим, что помимо border существует еще и внешняя рамка или «обводка» outline. У нее аналогичная запись, но ей нельзя задать какую-либо сторону отдельно, то бишь только всему элементу.

Еще одна особенность обводки outline — она не учувствует в расчёте размера бокса и строится после border и, соответственно, может залезать на соседние элементы.

У обводки есть уникальное свойство outline-offset, которое отвечает за отступ от элемента или рамки. Причем, принимает как положительные значения — отступ во вне, так и отрицательные — обводка сожмётся внутрь.

Пару слов про скругление углов border-radius — мы уже знаем, что можно задавать скругление каждому углу отдельно. Оказывается, для этого даже есть специальные отдельные свойства — border-top-left-radius, border-top-right-radius, короче, border-угол-radius.

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

/* горизонтальный радиус 30px, вертикальный 15px */
border-top-right-radius: 30px 15px;

Всё это безобразие можно записать и в короткой форме border-radius — радиусы задаются через /, при этом можно также задать сразу для всех углов:

/* горизонтальный радиус всех углов 10px, вертикальный 5px */
border-radius: 10px / 5px;

/* разные горизонтальные и вертикальные радиусы у каждого угла */
border-radius: 10px 20px 30px 40px / 5px 15px 25px 35px;

Далее мы переходим к обширной теме — фоновое изображение рамки и семейство свойств отвечающих за это — border-image.

За источник изображения отвечает свойство border-image-source и его синтаксис аналогичен свойству background-image, но для рамок.

border-image-source: url("image.jpg");

Однако, свойство для рамок работает немного иначе — по умолчанию изображение не растягивается как подложка под рамкой, как ожидается, а будет раскидано по углам рамки.

Дело всё в том, что рамка по свой сути имеет аж 9 областей — 4 угла, 4 стороны и центр. По умолчанию, браузер не умеет подстраивать изображение под задачи рамки, поэтому просто пихает его по углам.

За нарезку фонового изображения на области для рамки отвечает свойство border-image-slice — оно принимает от одного до четырёх числовых значений и работает по сути как функция rect() которую мы уже разбирали в Мастерских.

Кстати, свойство принимает какие-то условные единицы, то есть в самом свойстве, почему-то не надо ставить px — выдаст ошибку. Одно значение задаёт отступы от своих краёв для всех линий, а отдельно заданные идут в стандартном порядке — верх, право, низ, лево:

border-image-slice: 60; /* нарезка как на картинке выше */
border-image-slice: 10 20 30 40; /* каждая линия отдельно */

Таким образом, мы нарезаем изображение на те самые 9 частей и уже с ними работает браузер. По умолчанию, центральная область скрывается, но это можно изменить подставив в конце значений нарезки ключевое слово fill — тогда центральная часть перекроет фон, но не перекроет контент блока.

Изображение на сторонах, по умолчанию, растягиваются под всю длинны рамки, что далеко не для всех ситуаций подойдет. Но этим поведением можно управлять с помощью свойства border-image-repeat — он отвечает за способ заполнения фона по сторонам рамки. Именно по сторонам!

Свойство работает похожим на background-repeat образом, но по умолчанию имеет свой свойство stretch — которое, как раз, растягивает изображение по сторонам. Остальные значения, такие же:

  • repeat — повторяет части в размере отрезка, заполняя сторону полностью, при этом обрезает изображение в конце, если оно не поместилось.
  • round — работает абсолютно также как и у фона блока, крайне полезный и универсальный вариант.
  • space — тоже самое, работает аналогично значению из фона блока, но в тренажёре пишут мол, не везде поддерживается и часто заменяется на значение repeat.

Следующее свойство border-image-width — оно отвечает за размер уже нарезанных областей. Синтаксис похож на margin — одно значение для всех сторон, два для горизонтальных и вертикальных, четыре для всех сторон отдельно.

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

Расчёт идет от внешней границы рамки. Если размер фонового изображения области рамки задать больше чем размер рамки, то изображение начнёт залезать на фон блока, даже если не задан fill.

И последним рассмотрим свойство border-image-outset — оно отвечает за смещение фонового изображения рамки от элемента. Работает примерно как outline-offset, но принимает только положительные значения.

Фигуры из рамок

У рамок есть одно интересное свойство — каждая сторона строится по сути в виде трапеции, а при нулевом размере блока превращается в треугольник.

Таким образом, у нас в арсенале фигур еще две — квадраты и прямоугольники строить легче всего, круги и эллипсы можно строить через border-radius, а теперь и треугольники с трапециями.

Вторая часть про рамки посвящена такой мини-мастерской — мы строим стрелки и некоторые элементы интерфейса. Насколько это применяется в реальной жизни вопрос открытый, но прикольно. Конспектировать там, правда, нечего.

Испытания

Два испытания и оба на рамки, с фонами мы, видимо, наигрались в Catademy или как её там. Первое испытание на круглую рамку:

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


Тонкости получаются какие-то не тонкие, я надеялся будет одна коротенькая статья. Ну да ладно! В следующий раз быстренько разберёмся с тонкостями в оформлении текста и посмотрим на CSS-таблицы.

Спасибо большое за внимание! Я стараюсь ускорять темп, так как тренажёры затянулись уже что-то.

По поводу ссылок на предыдущие статьи — я решил пока перестать городить их тут, это тот еще геморрой и занимают они место, не очень красиво. Я скорее всего как-нибудь сделаю такой «пост-sitemap» и буду просто ссылаться на него, а пока пусть будет просто чистенько.

А вот соц.сеточки я оставлю! Я, кстати, завёл еще страницу на Facebook и заодно буду оставлять свой Instagram. Максимальное присутствие!

Telegram — Twitter — Instagram — Facebook — VK

Заходите куда удобно вам и подписывайтесь! Еще раз спасибо за внимание!