<divelopers>
1.13K subscribers
22 photos
1 video
1 file
292 links
Рандомные мысли про HTML, CSS, доступность, пользовательские интерфейсы, производительность, браузеры и веб-стандарты.

Автор: @alexnozer
Download Telegram
You don't know HTML: <select size> и <select multiple>

У элемента <select> есть ряд дополнительных возможностей, которые крайне редко используются. Причина та же, по которой разработчики не любят сам <select>: невозможность стилизации. К счастью, эта проблема уже решается.

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

Стандартный <select> отображается в виде блока с выбранным значением и небольшой стрелкой. При нажатии отображается выпадающий список с опциями. Выбор опции закрывает список и меняет текущее значение в блоке.

Если установить атрибут size со значением >1, то вместо блока с выпадающим списком отобразится прокручиваемый контейнер с опциями — listbox. Атрибут определяет, сколько опций должно быть видно в виджете.

Нажатие по опции делает её выбранной и снимает выбор с другой опции. При фокусе на listbox выбранную опцию можно менять стрелками вверх/вниз. По смыслу похоже на группу радио-кнопок, но listbox реализует другой паттерн.

Атрибут multiple включает множественный выбор опций. Как и с атрибутом size >1, при добавлении multiple вместо блока с выпадающим списком будет отображаться listbox. По смыслу это аналог группы флажков.

Нажатие по опции выбирает её, но не снимает выбор с других. Повторное нажатие по выбранной опции снимает выбор. Меняется поведение клавиатуры: стрелки навигируются по опциям, а Space выбирает/снимает выбор.

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

По умолчанию <select multiple> отображается как listbox с 4-мя видимыми опциями. Атрибут size можно использовать в сочетании с multiple для переопределения стандартного количества видимых опций.

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

#ydkhtml
7👍1🌚1👨‍💻1
Customizable select listbox

В понедельник я рассказывал об атрибутах size и multiple элемента <select>, которые позволяют превратить его в listbox и добавить множественный выбор опций. Это была подводка к сегодняшнему посту о стилизации listbox.

В Chrome 135 добавили поддержку стилизации элемента <select> на основе предложения «Customizable Select Element» от OpenUI. Сейчас это работает только с обычным <select>, атрибуты size и multiple не поддерживаться.

Команда Chrome продолжает работу и поделилась намерением внедрить стилизованный listbox. Это добавляет поддержку атрибутов size и multiple, делая listbox и его опции полностью стилизуемыми.

Брехт Де Рют написал у себя в блоге про грядущее обновление <select> со множественным выбором. Статья описывает некоторые изменения поведения мыши и клавиатуры, а также приводит примеры стилизации.

Как и с обычным <select>, свойство appearance: base-select меняет режим отрисовки виджета. Вместо системного компонента, который зависит от ОС, рисуется виджет на основе HTML и CSS с минимальными стилями.

В таком режиме появляется доступ к внутренним частям компонента, опциям, галочке выбранной опции, а также возможность вкладывать внутрь <select> и <option> другие HTML-элементы, например <svg> или <img> для иконок.

Меняется взаимодействие мышью и клавиатурой. Не нужно удерживать Ctrl при клике для выбора/снятия выбора с опции. Но теряется сочетание Ctrl + A и Ctrl + Arrow для выбора всех опций разом и последовательного выбора.

Что касается стилизации, то показан красивый интерфейс выбора жанров музыки, который выполнен в виде сетки. Это достигается за счёт возможности обернуть все опции в <div> и добавить ему свойства CSS Grid.

Следующий пример в статье показывает сочетание атрибутов multiple и size="1". В этом случае рисуется <select> с выпадающим списком и флажками у опций. В режиме base-select доступны все расширенные возможности стилизации.

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

Возможности стилизации listbox планируют добавить в Chrome 145, который должен выйти уже сегодня. Но остаются некоторые нерешённые вопросы с элементом <selectedcontent>, который отображает выбранную опцию внутри <select>.

Дискуссии продолжаются. Брехт в конце статьи оставил ссылку на issue с обратной связью и поделился своими идеями. Другие браузеры пока не внедрили стилизованный <select>, но работы по внедрению начались в Firefox.

#html #css #ui
👍53🌚1🤝1
HTML Components: Componentizing Web Applications

Попалась мне интересная заметка W3C, которая хорошо подойдёт для нерегулярной рубрики «веб-археология». Называется она «HTML Components Componentizing Web Applications» и датируется аж 1998 годом.

Как известно, концепция веб-компонентов прорабатывалась в конце нулевых и была публично представлена Алексом Расселом на конференции Fronteers в 2011 году. Однако сама идея «компонентизации» HTML появилась гораздо раньше.

Команда из Microsoft подметила, что HTML со скриптами сильно разрастается при разработке веб-приложений и становится сложно формализовать логику и повторно использовать HTML. Была предложено концепция HTML Components (HTC).

Идея была в том, чтобы предоставить синтаксис для описания компонента и его свойств, методов, событий и логики для дальнейшего применения на разных страницах. Вот как это примерно выглядело (помните, 1998 год):

<HTML xmlns:PUBLIC="urn:HTMLComponent">
<PUBLIC:METHOD NAME="start"/>
<PUBLIC:METHOD NAME="stop"/>
<PUBLIC:PROPERTY NAME="direction" GET="getDir" SET="setDir"/>
<PUBLIC:EVENT NAME="onFlyFinished"/>
<PUBLIC:ATTACH EVENT="onclick" HANDLER="onClick"/>

<SCRIPT LANGUAGE="ECMAScript">
var direction = 0;
var x = 0;
var y = 0;
var xScaler = 0;
var yScaler = 0;
var bFlying = false;
var timer;

function start() {
switch (direction) {
case 0:
x = -100;
xScaler = 5;
y = 0;
yScaler = 0;
break;
case 1:
x = 0;
xScaler = 0;
y = -100;
yScaler = 5;
break;
case 0:
x = 100;
xScaler = -5;
y = 0;
yScaler = 0;
break;
default:
x = 0;
xScaler = 0;
y = 100;
yScaler = -5;
break;
}
bFlying = true;
element.style.position = "relative";
tick();
}

function stop() {
if (bFlying) {
window.clearTimeout(timer);
element.style.left = "0";
element.style.top = "0";
bFlying = false;
var eventElem = document.getElementsByTagname(
"public:event"
)[0];
var oEvent = createEventObject();
eventElem.fire(oEvent);
}
}

function setDir(dir) {
if (dir == "left")
direction = 0;
else if (dir == "top")
direction = 1;
else if (dir == "right")
direction = 2;
else
direction = 3;
}

function getDir() {
switch (direction) {
case 0:
return "left";
break;
case 1:
return "top";
break;
case 0:
return "right";
break;
default:
return "bottom";
break;
}
}

function tick() {
element.style.left = x;
element.style.top = y;
x += xScaler;
y += yScaler;
if (x == 0 && y == 0)
stop();
else
timer = window.setTimeout("tick()", 100);
}

function onClick() {
alert("x is '" + x + "%', y is '" + y + "%'.");
}
</SCRIPT>


Этот код определяет компонент с методами start и stop, параметром direction, событием onFlyFinished и обработчиком события onclick, по которому вызывается метод onClick. Вся логика и методы описаны в <SCRIPT>.

Затем этот файл определения компонента должен был подключаться к конкретному элементу на странице через CSS-селектор и свойство behavior. После этого у элемента появлялись все указанные свойства и методы.

<HTML>
<HEAD>
<STYLE>
#flier {
behavior: url(fly.htc);
}
</STYLE>
</HEAD>
<BODY>
<H1 ID=flier>Flying titles!</H1>
<BUTTON onclick="document.getElementsByTagname('H1')[0].stop();">
Stop
</BUTTON>
<SCRIPT>
var flyingElem = document.getElementsByTagname( "H1" )[0];
flyingElem.onFlyFinished = "alert('finished flying!');"
flyingElem.direction = "left";
flyingElem.start();
</SCRIPT>
</BODY>
</HTML>


Вот такой прообраз веб-компонентов из конца 90-х. Сегодня компонент определяется в JS, подключается через <script>, поведение добавляется по имени элемента, а свойства, методы и события объединены в класс.

Если отбросить детали синтаксиса, то некое сходство с современным Custom Elements API проглядывается. Более того, нечто отдалённо похожее на старый синтаксис, но на новый лад сейчас проектируется в рамках Declarative Custom Elements.

#html #js
👍7😎21🌚1
You don't know HTML: inputmode

HTML предлагает встроенные типы текстовых полей ввода для некоторых распространённых типов данных:

- number
- email
- url
- tel
- password

У таких полей есть встроенные механизмы валидации данных, дополнительные возможности настройки и поведение. number позволяет ограничивать диапазон и управлять шагом, а password заменяет введённые символы на кружки.

Во встроенных текстовых полях виртуальная клавиатура адаптируется под данные. Но существующие типы полей не всегда уместны: number и tel не подходят для номера карты, идентификатора или номера посылки.

В таких случаях стоит использовать обычное текстовое поле type="text" в сочетании с атрибутом inputmode, который управляет виртуальной клавиатурой. Сверху можно добавить JS для валидации соответствующих данных. Если требуется поле ввода 8-значного кода, состоящего только из цифр, можно использовать такое сочетание:

<label for="order_id">
Код заказа
</label>
<input
type="text"
inputmode="numeric"
pattern="\d{8}"
id="order_id"
name="order_id"
size="8"
placeholder="12345678"
aria-describedby="order_id_hint"
>
<span id="order_id_hint">
8 цифр, например: 12345678
</span>

Атрибут inputmode принимает одно из следующих значений:

- none — виртуальную клавиатуру отображать не нужно;
- decimal — клавиатура с большими цифрами, дополнительными знаками и разделителями для дробных чисел;
- numeric — клавиатура с большими цифрами;
- text — значение по умолчанию. Отображается стандартная клавиатура;
- tel — клавиатура с большими цифрами и дополнительными символами * и #;
- search — стандартная клавиатура, адаптированная для поискового запроса, вместо кнопки ввода может отображаться, кнопка с лупой;
- email — стандартная клавиатура, адаптированная для адресов электронной почты, включает символ @;
- url — стандартная клавиатура, адаптированная для URL-адресов, включает символ /.

Наиболее интересны первые три значения. Остальные соответствуют встроенным типам полей и лучше использовать их вместо inputmode. Тем не менее они пригодятся при создании собственных полей на базе contenteditable.

<p id="custom-label">
Email
</p>
<div
class="custom-input"
contenteditable
role="textbox"
inputmode="email"
aria-labeledby="custom-label"
...
></div>

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

#ydkhtml
🔥1210👾3🌚1
Один большой CSS-файл или несколько маленьких?

Ситуация: у главной страницы интернет-магазина довольно низкий синтетический показатель производительности в Pagespeed. Сама страница состоит из шапки, hero-баннера, сетки из 8 карточек, формы подписки и подвала.

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

Сайт устроен так, что стили разных разделов и компонентов объединяется в один CSS-файл, который подключается в <head>. Он блокирует отрисовку, браузеру нужно скачать и разобрать файл, прежде чем что-то рисовать.

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

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

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

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

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

Кэш в мобильных браузерах может быть вытеснен из-за более жёстких квот на дисковую память (cache eviction), даже если он технически валиден и время жизни не истекло. В итоге новая холодная загрузка большого файла.

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

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

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

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

С разделением файлов появляются накладные сетевые расходы. Каждый файл — отдельный запрос. Современные протоколы HTTP/2 и HTTP/3 по большей части решают проблему. Но загружать слишком много тоже не стоит.

Небольшие файлы также кэшируются. Изменение стилей корзины затронет только файл со стилями корзины и кэш инвалидируется только для этого файла. Остальные стили извлекутся из кэша.

При вытеснении кэша на мобильных больше шансов, что хотя-бы часть файлов сохранится в кэше. Тогда как удаление одного большого файла сведёт кэш стилей на нет. Частичный кэш лучше его полного отсутствия.

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

#performance #css
114🤨7🌚1
Кнопки и ссылки

Время идёт, а дискуссии о кнопках и ссылках продолжаются. Недавно в чате веб-стандартов как раз обсуждали эту тему. Вроде бы всё очевидно: есть кнопка <button>, есть ссылка <a>, это разные элементы. Но неоднозначность сохраняется.

Ссылка <a> достаточно навороченный и сложный элемент. Никита Дубко когда-то целый доклад об этом сделал, рекомендую посмотреть. Суть элемента <a> крутится вокруг URL-адресов, навигации и контекстных действий над этими URL-адресами.

Кнопка <button> — не менее простой элемент. Исходя из встроенных возможностей, кнопка про управление формами, переключение поповеров, декларативный вызов команд и запуск произвольного JS-обработчика при нажатии.

Различия улавливаются: <a> про работу с URL-адресами, а <button> про работу с формами, UI-элементами страницы и произвольным JS. На сайтах, где в основном текстовый контент, понятно, что нужно использовать.

Ситуация усложнилась с развитием веб-приложений. Дизайнеры стали рисовать ссылки на другие страницы в виде кнопок и кнопки вызова действий в виде ссылок. Грань между подчёркнутым текстом и прямоугольником с текстом по центру размылась.

Разработчики не особо задумываясь используют <button> с location.href, если в макете нарисована кнопка и <a> с заглушкой в href и обработчиком нажатия, если в макете нарисован текст с подчёркиванием.

<!--
Код иллюстративный,
не надо так делать!
-->

<!-- «Кнопка-ссылка» -->
<button
class="button"
onclick="goTo('/catalog')"
>
Каталог
</button>

<!-- «Ссылка-кнопка» -->
<a
class="link"
href="#"
onclick="closeModal()"
>
Закрыть
</a>


Битва с дизайном проиграна: кнопки и ссылки рисуются по настроению, чутью и общепринятым шаблонам, а не по реальному назначению. CTA на баннере главной страницы магазина в 99% случаев будет ссылкой, которая выглядит как кнопка.

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

Вариативность дизайна и назначения порождает компоненты <ButtonLink> и <LinkButton>. Иногда появляются «универсальные бойцы», вроде <Action>, которые работают условно, в зависимости от переданных параметров (пропсов).

Так, к примеру, работает веб-компонент <sl-button>, который принимает атрибуты, свойственные как для <a>, так и для <button> и под капотом решает, какой HTML-элемент использовать. А его атрибут variant определяет внешний вид.

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

<!-- Иллюстрация идеи -->

<!-- Стандартная кнопка -->
<button
type="button"
commandfor="cart-drawer"
command="show-modal"
>
Корзина
</button>

<!-- Ссылка на базе кнпоки -->
<button
type="link"
href="/catalog"
>
Каталог
</button>


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

#html #ui
11🔥61🌚1
Прямая трансляция Я 💛 Фронтенд 2026

Сегодня состоится конференция Я 💛 Фронтенд 2026, на которой я вступлю с докладом про веб-компоненты. Присоединяйтесь к трансляции, начало в 11:00 по Москве, мой доклад в 11:50.
👍136🥰4🔥2😍1🌚1
50 оттенков веб-компонентов.pptx
29.5 MB
50 оттенков веб-компонентов

Только что выступил с докладом «50 оттенков веб-компонентов». Как и обещал, делюсь презентацией с выступления.
18👍6🔥2🌚1😘1
You don't know HTML: категория и контентная модель

Как разработчики определяют, какие HTML-элементы можно вкладывать в другие HTML-элементы? В целом, на уровне интуиции и логики. Понятно, что <li> должен быть в <ul> или <ol>, <td> в <tr>, а тот в <table>.

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

Категории — это группы элементов, объединённые какими-то общими свойствами. Один HTML-элемент может принадлежать сразу к нескольким категориям или не принадлежать ни к одной из них. Всего есть 18 категорий.

Контентная модель — это описание того, какие конкретные элементы или категории элементов допустимы. Соответствие контентной модели родительского элемента и категории дочернего — и есть правила вложенности.

Контентная модель неупорядоченного списка <ul> — ноль или более элементов <li> и script-supported elements. Это значит, что внутрь списка могут быть вложены только элементы <li>, <script> и <template>.

Контентная модель элемента списка <li>flow content, значит можно вложить любые элементы этой категории. Сам <li> при этом не относится к какой-либо категорий, поэтому его нельзя никуда вкладывать, если не указано иное.

В некоторых случаях контентная модель жёстко ограничена конкретными элементами, а не категориями, как у таблиц. Иногда есть правила, что конкретный элемент должен быть в определённом месте, как у <details>.

Есть контентная модель под названием transparent. Внутрь «прозрачных» элементов можно вкладывать то, что можно вкладывать в их прямого родителя. Такая модель присуща некоторым элементам, среди которых <a>.

Помочь с определением вложенности может сайт Can I Include. Он как раз сравнивает категорию и контентную модель. Другой способ проверить корректность вложенности — использовать HTML Validator.

У неверной вложенности есть последствия:
- В некоторых случаях браузеры перестраивают DOM;
- Нарушается семантика, что влияет на доступность;
- Может серьёзно ухудшаться производительность;
- Могут ломаться инструменты, которые анализируют HTML (браузерные плагины, онлайн-сервисы).

#ydkhtml
👍132🌚1🤝1
Оптимизация загрузки встраиваемых видео без JS

При встраивании видео и других виджетов через <iframe> есть проблема: ресурсы загружаются даже если пользователь не взаимодействует с виджетом. Для решения проблемы используется техника фасадов, о которой есть отдельный пост.

Суть техники в том, чтобы вместо реального виджета показать максимально похожую визуально заглушку. При нажатии или наведении указателя на заглушку срабатывает обработчик, который подменяет её на реальный <iframe> виджета.

Для плееров YouTube и Vimeo есть веб-компоненты, которые реализуют технику фасадов: отображают обложку видео с фейковой кнопкой воспроизведения, а при нажатии подменяют всё на реальный <iframe> с плеером.

Это хорошо работает и оптимизирует загрузку ресурсов, но требует реализации на JS или подключения веб-компонента. Штефан Бауэр предлагает альтернативный способ реализации фасадов с помощью <details> и loading="lazy":

<details>
<summary>
<img
src="cover.jpg"
alt="Смотреть видео"
>
<svg aria-hidden="true">
<!-- фейковая кнопка -->
</svg>
</summary>
<div>
<iframe
src="..."
loading="lazy"
>
</iframe>
</div>
</details>


<iframe> с атрибутом lodaing="lazy" работает по аналогии с <img>. Содержимое фрейма и связанные ресурсы не загружаются до тех пор, пока он не окажется в области просмотра или достаточно близко к ней.

Если поместить такой фрейм в <details>, то он будет скрыт. Это значит, что фрейм окажется в области просмотра только в момент открытия <details>. В <summary> можно поместить обложку и фейковую кнопку, а сам элемент скрывать при открытии <details>.

details[open] > summary {
visibility: hidden;
}


Пока пользователь не нажмёт на <summary> c обложкой, фрейм не будет загружаться. После нажатия <details> раскрывается, фрейм начинает загружаться, а <summary> скрывается. Получается ленивая загрузка виджетов без JS.

#html #performance
👍13🔥94🤯3🤩1🌚1
Современный CSS

Делюсь сайтом, на котором собраны сниппеты современного CSS, которые заменяют решения на JS, функции препроцессоров, хаки и более громоздкие конструкции самого CSS. Есть фильтрация по уровню поддержки.

Помимо сниппетов на сайте есть разделы со статьями, ссылками на ресурсы, новинками CSS и песочницами (пока только для резиновой типографики). Сайт обновляется, поэтому имеет смысл подписаться на рассылку или RSS.

#css
🔥105👍42🌚1
Подборка ссылок

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


Standard HTML Video & Audio Lazy-loading is Coming!

Скотт Йель поделился новостью, что его команде удалось стандартизировать ленивую загрузку аудио и видео. Работа началась ещё в 2024 году: описание и обсуждение предложения, тесты веб-платформы (WPT), патчи в Firefox и WebKit.

<video
loading="lazy"
autoplay
playsinline
muted
controls
src="path/to/sloth.webm"
poster="path/to/sloth.jpg"
></video>



aria-haspopup might not do what you think it does

Мануэль Матузович пишет о неверном использовании атрибута aria-haspopup. У попапа должна быть роль menu, listbox, tree, grid или dialog. Не во всех случаях aria-haspopup уместен. Я на днях с этим столкнулся на реальном проекте.


An in-depth guide to customising lists with CSS

Подробный гайд по стилизации списков с использованием разных возможностей CSS от Ричарда Раттера. Я тоже писал об этом:

- You don't know HTML: нумерованные списки
- Стилизация счётчиков списка
- counters() и counter-style


Practical guide to the <img> element: from the basics to LCP

Джоан Леон рассказывает об элементе <img> с точки зрения производительности: атрибуты width и height, <picture> и современные форматы изображений, decoding, loading, fetchpriority оптимизацию LCP и CDN.


Stylable Select

Я писал про стилизуемый <select> и работы по дальнейшему развитию возможностей стилизации. Брехт Де Рёйте, который активно вовлечён в эту тему, поделился коллекцией примеров стилизуемого селекта на Codepen.


csskit

Кит Сиркель, браузерный инженер, работающий над Firefox, поделился своим проектом csskit. Это написанный на Rust инструмент для работы с CSS: форматтер, линтер, минификатор, транспилятор, бандлер и анализатор в одном флаконе.

#html #css #a11y #performance
1👍8🥴1🌚1
Создание сайтов с использованием LLMS*

На пост именно с таким заголовком я наткнулся в блоге Джима Нильсена. Вопреки, речь пойдёт не об ИИ, поэтому добавил звёздочку. Речь о подходе, который автор назвал «Lots of little HTML pages», сокращённо LLMS.

С помощью Cross-document View Transition можно создавать плавные переходы между разными страницами на CSS. BFCache делает переходы «вперёд»/«назад» мгновенными. Маленькие и лёгкие страницы загружаются быстро.

Эти три особенности позволяют вместо кнопки бургер-меню на JS сделать ссылку на отдельную страницу с меню, которая быстро загружается за счёт малого размера и плавно отображается за счёт View Transition.

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

Именно так бургер-меню, поиск и фильтрация реализованы в блоге Джима. Чтобы наглядно увидеть суть, советую пощёлкать сайт. А реализация предельно простая: несколько отдельных страниц и обычные ссылки <a>.

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

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

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

#html #css #ui
🔥7👍4🤔32🌚1🤨1
Кампания Build Awesome

Font Awesome запустила кампанию Build Awesome на Kickstarter. Ранее они уже проводили подобное с Web Awesome: собрали денег и выпустили ребрендинг библиотеки Shoelace с улучшениями и новыми PRO функциями.

На этот раз планируется ребрендинг Eleventy — популярного генератора статических сайтов. Его создатель — Зак Лезерман, как и создатель Shoelace — Кори ЛаВиска, перешли работать в Font Awesome вместо со своими проектами.

Учитывая историю с Web Awesome и данные на странице кампании, получается следующее:

- Следующая мажорная версия Eleventy (4.0) выходит под новым названием Build Awesome. Просто новое название, проект по-прежнему останется с открытым исходным кодом, сохранит синтаксис, API и будет совместим с существующими плагинами;
- Появится платформа, которая должна упростить создание и поддержку сайтов. Предположительно это веб-интерфейс с админкой, где можно будет собрать сайт с помощью Eleventy, выкачать статику, опубликовать на CDN и управлять контентом;
- Появятся шаблоны для блога, портфолио и персонального сайта для быстрого старта, а также плагины для использования иконок Font Awesome и веб-компонентов Web Awesome;
- Появятся платные PRO функции: коллаборативное редактирование, платформа для превью и публикации, премиум-шаблоны, DevTools для проверки качества сайтов, инструменты миграции, премиум поддержка и, конечно же, ИИ функции.

Также в зависимости от суммы сборов заявлены дополнительные функции:

- Система темизации
- Плагин для SEO/Favicon/OpenGraph
- Инструменты для новостной рассылки
- Интеграция со Stripe
- Инструменты синдикации для социальных сетей
- Аналитика
- Формы
- Плагин для шрифтов
- PWA с поддержкой local-first/offline-first
- Медиа-библиотека аудио/видео

Чтож, посмотрим, что из этого выйдет. Для любителей Eleventy это, возможно, тревожный звоночек. С другой стороны, это обеспечит проекту стабильность и долговечность, авторам тоже нужно кормить себя и семью.

Ядро Web Awesome и основные компоненты остались доступными в виде проекта с открытым исходным кодом при ребрендинге Shoelace. Аналогично должно быть с Eleventy. PRO функции не обязательны, а ядро сохраняется как есть.

#tools
1🤔21💩1🌚1💯1👨‍💻1
Применение новых функций веб-платформы с учётом кроссбраузерности

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

Знакомо? Это как мем наоборот: пока кто-то живёт в 2026, мы живём в 2018. То есть используем только стабильные функции которые давно и широко поддерживаются. Как тогда использовать все эти классные новые функции?

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

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

View Transition можно добавить прямо сейчас. Если браузер не умеет, функция будет пропущена (при наличии проверки) и ничего не сломается, просто не будет плавного перехода. Многие функции можно использовать по такому принципу.

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

.section {
background-image:
url('section-gradient.jpg')
;
background-image:
conic-gradient(/*...*/)
;
}


Директива @supports и JS API CSS.supports() позволяют проверять поддержку новых функций CSS и реализовывать резервные. Аналогично в JS можно проверить наличие того или иного свойства, метода или объекта.

Для более сложных функций, как Popover API, Anchor Positioning или Invoker Commands, требуются полифилы. Нужно решить, готовы ли вы на частичное замещение функции у той части аудитории, у которой она не доступна.

Если функция отсутствует у 5-10% пользователей, кажется, что уместно добавить для них полифил и оставить 90-95% пользователей со встроенной функцией. Если соотношение другое, возможно, стоит повременить.

С оценкой зрелости функций поможет Baseline. У каждой функции есть один из трёх статусов:

- Limited Availabity — функция внедрена в один или несколько основных браузеров, но не во все;
- Newly Available — функция внедрена во все основные браузеры относительно недавно, поддержка узкая;
- Widely Available — функция внедрена во все основные браузеры как минимум 2.5 года и широко поддерживается.

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

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

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

#html #css #js #web_api
👍62🌚1🤝1
Бюджеты ресурсов для разработки производительных сайтов на 2026 год

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

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

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

Тестовые устройства, которые отражают 75й перцентиль пользовательского опыта:

Смартфоны:

- Samsung Galaxy A24 4G
- Samsung Galaxy A16 4G
- Samsung Galaxy A07 4G
- Xiaomi Redmi Note 13 Pro 4G
- Samsung Galaxy A51
- Motorola Moto E15

Ноутбуки:

- HP 14 dq3500nr
- Или аналоги в пределах 250$, на процессоре Celeron, c модулем eMMC и работающий на WIndows.

(сравните их характеристики со своим рабочим сетапом)

Тестовые параметры сети:

- Входящая скорость 9 Мбит/с;
- Исходящая скорость 3 Мбит/с;
- Задержка (RTT) 100 мс.

Эти устройства и параметры сети — базовый уровень, на который стоит ориентироваться при анализе производительности. Бюджеты рассчитаны на загрузку страницы за 3 и 5 секунд. Это приемлемые показатели для данных условий.

Из-за разных подходов к разработке выделяются две категории сайтов для формирования бюджетов:

- Сайты с «лёгким JS», где JS составляет 15% от объёма всех ресурсов на критическом пути. Это традиционные MPA с точечным JS для прогрессивного улучшения или подходы с островной архитектурой;
- Сайты с «тяжёлым JS», где JS составляет 50% от объёма всех ресурсов на критическом пути. Это соответствует подходам SPA и SSR с гидратацией на стороне клиента.

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

Разделение ресурсов на JS и всё остальное обусловлено тем, что JS — самый тяжёлый с точки зрения производительности ресурс. 500 кб JS не то же самое, что 500 кб изображения. «Остальное» включает в себя HTML, CSS, изображения и данные.

Теперь, когда все пояснения даны, собственно, сами бюджеты:

Загрузка за 3 секунды сайтов с «лёгким JS»:

- 0.3 мб JS
- 1.7 мб остальные ресурсы
- 2.0 мб всего ресурсов

Загрузка за 3 секунды сайтов с «тяжёлым JS»:

- 0.62 мб JS
- 0.62 мб остальные ресурсы
- 1.2 мб всего ресурсов

Загрузка за 5 секунд сайтов с «лёгким JS»:

- 0.57 мб JS
- 3.2 мб остальные ресурсы
- 3.7 мб всего ресурсов

Загрузка за 5 секунд сайтов с «тяжёлым JS»:

- 1.15 мб JS
- 1.15 мб остальные ресурсы
- 2.3 мб всего ресурсов

Как трактовать эти бюджеты? Если речь о сайте электронной коммерции (отрисовка HTML на сервере, точечный прогрессивный JS для интерактивности, категория «лёгкий JS»), то для загрузки за 3 секунды на целевом устройстве и сети нужно:

- чтобы HTML страницы, блокирующие стили и LCP-изображение в сумме составляли 1.7 мб;
- чтобы весь блокирующий JS (не defer или async) в сумме составлял 0.3 мб.
- чтобы общий вес этих ресурсов не превышал 2 мб.

Если речь о SPA, то для загрузки за 3 секунды нужно:

- чтобы начальный HTML, стили и LCP-изображение в сумме составляли 0.62 мб;
- чтобы весь JS приложения с данными в сумме составляли 0.62 мб.
- чтобы общий вес ресурсов не превышал 1.2 мб.

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

#js #performance
1👍53🔥1🥰1🌚1
Abusing Customizable Select

Патрик Броссет экспериментирует с новым стилизуемым <select> и некоторыми другими возможностями CSS. В статье он показывает 3 демо и описывает шаги и методы их реализации:

- Изогнутое меню выбора директории;
- Выбор карты из колоды в виде веера;
- Круговой выбор эмодзи.

Для каждого демо есть видео (на случай если браузер не поддерживает стилизуемый <select>), а также Codepen с полной реализацией. Все демо по своему интересные и демонстрируют возможности нового API.

#html #css #ui
👍92🔥1🌚1🤗1
Проблемы карточек, обёрнутых в ссылки

Карточки, обёрнутые в <a>, достаточно распространённый шаблон в Интернете. Дизайнеры хотят, чтобы нажатие в любое место карточки вызывало переход на соответствующую страницу. Самый простой способ — обернуть всё в <a>.

<a href="...">
<article class="card">
<img
src="..."
class="card__image"
alt="Чёрные беспроводные наушники Sony WH‑1000XM5, вид сбоку."
>
<h2 class="card__title">
Беспроводные наушники Sony WH‑1000XM5 (Чёрные)
</h2>
<p class="card__vendor">
Sony
</p>
<p class="card__price">
299 $
</p>
</article>
</a>


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

Чёрные беспроводные наушники Sony WH‑1000XM5, вид сбоку. Беспроводные наушники Sony WH‑1000XM5 (Чёрные) Sony 299 $


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

Быстро исправить проблему можно путём добавления на ссылку атрибута aria-label или aria-labelledby с привязкой к заголовку. Оба способа переопределяют имя, генерируемое из тестового контента. Всё содержимое не будет зачитываться.

<a 
href="..."
aria-label="Беспроводные наушники Sony WH‑1000XM5 (Чёрные)"
>
<!-- ... -->
</a>

<a
href="..."
aria-labelledby="heading"
>
<!-- ... -->
<h2
id="heading"
class="card__title"
>
Беспроводные наушники Sony WH‑1000XM5 (Чёрные)
</h2>
<!-- ... -->
</a>


При использовании aria-label важно, чтобы текст в атрибуте совпадал с видимыми текстом заголовка согласно критерию 2.5.3 Label in Name. С aria-labelledby это гарантируется за счёт связи с заголовком.

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

<a href="...">
<!-- ... -->
<a
href="..."
class="card__vendor"
>
Sony
</a>
<!-- ... -->
</a>


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

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

<article class="card">
<!-- ... -->
<h2 class="card__title">
<a
href="..."
clasd="card__link"
>
Беспроводные наушники Sony WH‑1000XM5 (Чёрные)
</a>
</h2>
<a
href="..."
class="card__vendor"
>
Sony
</a>
<!-- ... -->
</article>


.card {
position: relative;
}

.card__link::before {
content: '';
position: absolute;
inset: 0;
z-index: 1;
}

.card__vendor {
position: relative;
z-index: 2;
}


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

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

Более подробно эту технику описывает Хейдон Пикеринг в онлайн книге Inclusive Components. Также тему проблем с карточками затрагивает Адриан Розелли в своей статье Block Links, Cards, Clickable Regions, Rows, Etc.

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

#html #css #a11y
222👍2🌚1💯1🆒1
CSS Web Components

Будучи набором браузерных API, веб-компоненты можно использовать самыми разными способами. Некоторые из таких способов применения получили в сообществе собственные названия. Один из них — CSS Web Components.

Суть подхода в том, чтобы взять от Custom Elements API минимум возможностей: никаких Shadow DOM, классов, методов жизненного цикла и JS в целом. Только пользовательские HTML-элементы с атрибутами в разметке и стили.

Любой несуществующий в HTML элемент обрабатывается браузером как HTMLUnknownElement. Он отображается, попадает в DOM со всеми дочерними узлами, доступен через DOM API, стилизуется с помощью CSS.

Но HTMLUnknownElement не валиден с точки зрения стандарта. Валидатор покажет ошибку и проигнорирует неизвестный элемент и всё его поддерево. В свою очередь пользовательские элементы — это валидные экземпляры HTMLElement.

<!--
HTMLUnknownElement, не валиден
-->
<sidebarpanel>
<!-- ... -->
</sidebarpanel>

<!--
HTMLElement, валиден
-->
<sidebar-panel>
<!-- ... -->
</sidebar-panel>


Кроме того, у пользовательских элементов можно задавать произвольные атрибуты без префикса data-*, если они не пересекаются со стандартными глобальными атрибутами, например id, class, translate, lang и так далее.

У пользовательских элементов по умолчанию встроенная роль generic, как у <div> или <span>. Поэтому они сами по себе ничего не значат и не ломают семантику. Если нужно, можно указать глобальные aria-* атрибуты и role.

Всё это в совокупности можно использовать как альтернативу <div> и <span> для более осмысленного именования контейнеров, обёрток и компонентов, для которых нет подходящих семантических HTML-элементов.

<!--
Контейнер для ограничения
ширины контента и центровки
-->
<page-container width="lg">
<!-- ... -->
</page-container>

<!--
Контейнер для отображения
изображений в виде сетки
-->
<image-grid col="3" gap="sm">
<!-- ... -->
</image-grid>

<!--
Компонент бейджа
-->
<ui-badge variant="primary">
<!-- ... -->
</ui-badge>


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

Примеров можно придумать много. Кто-то делится своими идеями и практическими примерами. А кто-то даже свою CSS-методологию построил на основе CSS Web Components. Всё это в целом выглядит непривычно, но интересно.

- You can make up HTML tags
- Replace Divs With Custom Elements For Superior Markup
- Custom Element Examples (Without Javascript)
- Responsive Columns: Build Amazing Layouts With Custom HTML Tags
- TAC: A new CSS methodology
- 3 Examples of the TAC Methodology In Action

Таким образом CSS Web Components — это подход к вёрстке, когда <div> и <span> заменяются на незарегистрированные (без определения в JS) пользовательские элементы с осмысленными названиями, атрибутами и соответствующими стилями.

#html #css
👍6🔥61🤩1🌚1🙈1
Диалог, форма, список выбора и нарушения WCAG

При аудите столкнулся с компонентом переключения страны/валюты в магазине. Он использует кнопку раскрытия диалога, в котором находится форма со списком выбора (listbox), внутри которого опции в виде кнопок отправки формы:

<button
type="button"
aria-expanded="false"
aria-haspopup="dialog"
aria-controls="popover-id"
aria-label="Change country or currency"
>
United States (USD $)
</button>
<x-popover
role="dialog"
id="popover-id"
>
<form action="...">
<!-- скрытые поля -->
<x-listbox
role="listbox"
aria-activedescendant="option-us"
>
<!-- другие опции -->
<button
type="submit"
id="option-gb"
name="country_code"
value="GB"
role="option"
>
United Kingdom (GBP £)
</button>
<button
type="submit"
id="option-us"
name="country_code"
value="US"
role="option"
aria-selected="true"
>
United States (USD $)
</button>
<!-- другие опции -->
</x-listbox>
</form>
</x-popover>

Достаточно маленький компонент, а нарушает сразу несколько критериев WCAG:

- 2.1.1 Keyboard — в списке выбора не реализована соответствующая механика клавиатурного взаимодействия. Фокус должен попадать на listbox, опции переключаться стрелками/Home/End с фокусом через aria-activedescendant;

- 2.5.3 Label in Name — имя кнопки раскрытия диалога не совпадает с видимой подписью. Видимая подпись — «United States (USD $)», а программно заданное с помощью атрибута aria-label имя — «Change country or currency»;

- 3.2.2 On Input — выбор опции из списка приводит к отправке формы и смене контекста. Из-за реализации опций на основе кнопок с атрибутом type="submit" при нажатии происходит отправка формы с перезагрузкой страницы;

- 3.3.2 Labels or Instructions — нет видимой подписи у кнопки раскрытия диалога и поля выбора. В первом случае подпись задана через aria-label, а во втором случае не задана ни видимым элементом, ни программно;

- 4.1.2 Name, Role, Value — у поля выбора нет ассоциированного имени. У listbox должно быть имя, которое задано одним из способов. В данном случае имя не задано ни одним из способов.

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

<p id="label-id">
Change country or currency
</p>
<button
type="button"
id="button-id"
aria-expanded="false"
aria-haspopup="dialog"
aria-controls="popover-id"
aria-labelledby="label-id button-id"
>
United States (USD $)
</button>
<x-popover
role="dialog"
id="popover-id"
>
<form action="...">
<!-- скрытые поля -->
<ul>
<!-- другие кнопки -->
<li>
<button
type="submit"
name="country_code"
value="GB"
>
United Kingdom (GBP £)
</button>
</li>
<li>
<button
type="submit"
name="country_code"
value="US"
aria-current="true"
autofocus
>
United States (USD $)
</button>
</li>
<!-- другие кнопки -->
</ul>
</form>
</x-popover>


Убран listbox, кнопка раскрытия получила видимую подпись и составное имя с помощью aria-labelledby, добавлен обычный список, убрана семантика option и состояние aria-selected, вместо него теперь aria-current, добавлен autofocus для установки фокуса при открытии диалога.

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

#html #ui #a11y
8👍5🤩2🌚1
Крис Койер про область видимости в CSS

Посмотрел запись доклада Криса Койера про область видимости в CSS с прошедшей в июне 2025 года конференции CSS Day. Другие доклады доступны в плейлисте на YouTube-канале конференции. Теперь пару мыслей о докладе.

Крис начал с того, что написание CSS, по сути, сводится к определению области видимости и заданию стилей для этой области. Селекторы — это область видимости. Вроде базовая мысль, но я с такой точки зрения об этом не думал.

Далее затрагиваются инструменты для автоматического ограничения области видимости через генерацию уникальных классов. Один из таких — CSS Modules. Интересно то, что это набор правил, а не конкретная реализация.

Прозвучала мысль, что если к синтаксису языка добавляется что-то нестандартное, то не стоит использовать расширение .css и мимикрировать под обычный CSS. А CSS Modules добавляют нестандартные composes, :local и :global.

Обычно CSS Modules импортируются с помощью псевдо-импортов, которые не работают в JS и обрабатываются сборщиком. Раз так, то расширение файла могло быть, например, .mcss или .cssm, чтобы подчеркнуть отличие от CSS.

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

Далее упоминается подход CSS-in-JS, который помимо прочего обеспечивает область видимости через уникальные классы. По мнению Криса этот подход скорее CSS-in-React, поскольку тот не предлагает решения для стилей.

Это породило множество разных реализаций: styled-components, emotion, jss, и так далее. Они ничего особого не привнесли сообществу в глобальном смысле. Сегодня подход runtime CSS-in-JS пришёл в тупик и изжил себя.

Далее Tailwind, который обеспечивает область видимости иным способом. Не уникальными классами, а набором точечных классов, применяемых к конкретному элементу. Как и для Криса, это не для меня, но имеет место быть.

Отдельного говорится про хардкорные способы области видимости в веб-платформе: <iframe> (<object> сюда же) и Shadow DOM. Оба с нюансами и не очень удобные. В конце @scope — новый способ управления областью видимости.

В базовом виде @scope как-будто не имеет особого смысла. Того же эффекта можно добиться сейчас без него. Интересны более продвинутые техники, названные «Donut Scope», «DOM Blasters» и «Proximity». Это уже тема для отдельного поста.

#css
👍103🌚1😈1