Рандомные мысли про HTML, CSS, доступность, пользовательские интерфейсы, производительность, браузеры и веб-стандарты.
Автор: @alexnozer
Post #121
317
<D @alexnozer_dev
Showing posts older than #122 · Back to latest
Forwarded from MinskCSS/MinskJS

scroll-snap-target для указания элемента, который изначально должен быть привязан:.carousel {
overflow-inline: auto;
}
.carousel .origin {
scroll-start-target: auto;
}<div class="carousel">
<img src="img1.jpg">
<img src="img2.jpg">
<img src="img3.jpg" class="origin">
<img src="img4.jpg">
<img src="img5.jpg">
</div>
:snapped-x, :snapped-y, :snapped-inline и :snapped-block для стилизации привязанных элементов. Однако, принято решение отказаться от них в пользу новых Style Container Queries.scrollsnapchange и scrollsnapchanging для отслеживания изменений привязанных элементов при прокрутке в JavaScript. Вместе с ними добавляется новый тип события SnapEvent с соответствующим интерфейсом и набором свойств..element {
/* стили */
}
@media (max-width: 1024px) {
.element {
/* стили для экранов шириной 1024px и меньше */
}
}
@media (max-width: 768px) {
.element {
/* стили для экранов шириной 768px и меньше */
}
}max-width или Mobile First с min-width. Всё это может быть написано в одном файле или распределено по разным файлам и склеено в процессе сборки. Это может быть нативный CSS или SCSS. Не важно.<head>
<!-- ... -->
<link rel="stylesheet" href="base.css" media="all">
<link rel="stylesheet" href="mobile.css" media="(width < 768px)">
<link rel="stylesheet" href="tablet.css" media="(768px <= width < 1024px)">
<link rel="stylesheet" href="desktop.css" media="(width >= 1024px)">
<!-- ... -->
</head>
media="all" можно не указывать, но пусть будет для наглядности. К базовыми стилями относятся те, которые применяются вне зависимости от экрана. Это могут быть директивы @font-face, сбросы, общие стили и т.д.768px. Планшетные стили применяются на экранах шириной от 768px, до 1024px не включая. Десктопные стили применяются на экранах от 1024px и выше. В примере используется Media Query Range Syntax, который уже неплохо поддерживается.media взаимоисключающие. Во вкладке Styles в DevTools не будет каскада переопределений, это улучшает читаемость, упрощает отдадку и не заставляет отменять правила. Также всегда понятно, где искать нужные стили в проекте.media у <link>, браузер проверяет медиа-запрос на соответствие. Если он соответствует параметрам, файл загружается как обычно. А вот если не соответствует, то, вопреки ожиданиям, он всё равно загружается, но с более низким приоритетом и, что самое главное, не блокирует отрисовку. В итоге стили загружаются и применяются быстрее, а значит отрисовка тоже происходит быстрее.<form action="/user/change-avatar" method="post" enctype="multipart/form-data">
<label for="avatar">Take a photo</label>
<input type="file" id="avatar" accept="image/*" capture="user">
<button>Send</button>
</form>
capture и accept для <input type="file">. В примере мы говорим браузеру, что хотим использовать фронтальную камеру устройства (capture="user"), чтобы сделать фото (accept="image/*"). При нажатии на поле, вместо стандартного окна выбора файла, запустится приложение камеры в режиме съемки на фронтальную камеру. После снимка, файл изображения будет помещён в поле выбора файла и форму можно будет отправить на сервер.accept="video/*" capture="environment", для записи аудио — accept="audio/*" capture. Само собой, нужно дать браузеру доступ к камере и микрофону, иначе не заработает.<input> через Javascript и нарисовать его в <canvas>, вставить в <img>, <audio> или <video> для предпросмотра перед отправкой. Можно отправить данные на сервер при помощи Fetch API.@property и @starting-style теперь доступны во всех стабильных браузерах. Я написал об этом на основании того, что видел новость о добавлении @starting-style в Firefox.@starting-style, поэтому решил уточнить этот момент.@starting-style доступен с Firefox 127, но за специальным флагом и ещё не до конца реализован. Поэтому эта директива всё ещё не стала кроссбраузерной и она не доступна в Firefox 128.@starting-style. Но не всё из беты может попасть в финальный релиз, поэтому на самом деле не известно, когда это заедет.@property и @starting-style.@property позволяет управлять характеристиками пользовательских свойств. А именно: типом, наследованием и значением по умолчанию.@property --width {
syntax: "<length>";
inherit: false;
initial-value: 48px;
}--width, его значение будет преобразовано к типу <length>, оно не будет наследоваться и по умолчанию будет равно 48px. Это свойство можно будет использовать для анимации в @keyframes. Подробнее о @property.@starting-style даёт возможность задавать стили, которые будут применены при отрисовке элемента, когда значение display меняется с none на другое значение. С помощью этого механизма можно анимировать появление элемента.[popover]:popover-open {
opacity: 1;
transform: scaleX(1);
}
@starting-style {
[popover]:popover-open {
opacity: 0;
transform: scaleX(0);
}
}[popover]:popover-open {
opacity: 1;
transform: scaleX(1);
@starting-style {
opacity: 0;
transform: scaleX(0);
}
}opacity и transform плавно изменят свои значения. Подробнее о @starting-style.
<nav> с нумерованным списком <ol> с ссылками <a> внутри <li> будет выглядеть как хлебные крошки. В таких библиотеках используются более сложные селекторы с комбинаторами и иногда :has(), но всё ещё без классов.<link> в <head> и всё будет работать. У меня даже возникла идея сделать свою реализацию classless-библиотеки 🤔<label for>, с помощью которого можно задать имя встроенным элементам <input>, <textarea>, <select>, <button>, <meter>, <progress>, <output> и FACE (Form-associated Custom Elements). Если у элементов не заданы атрибуты aria-label и aria-labelledby, то текст из <label> используется как имя.aria-description/aria-describedby? На данный момент нет способа сделать это без ARIA. С новым элементом это может выглядеть так:<label for="password">Пароль</label>
<input type="password" name="password" id="password">
<description for="password">Пароль должен содержать не менее 8 символов, а также включать как минимум одну цифру, одну букву и один символ пунктуации.</description>
<h2 role="tab">heading tab</h2>
<div role="tab">
<h2>heading tab</h2>
</div>
role="presentation" (синоним role="none") и aria-hidden="true" на интерактивных элементах.<button role="presentation">
press me
</button>
<button aria-hidden="true">
press me
</button>
<div aria-hidden="true">
<button>press me</button>
</div>
<label>, aria-label, aria-labelledby и т.д.)input.showPicker(). Это выглядит как JavaScript-метод (так оно и есть), может возникнуть вопрос: причём тут HTML? На самом деле этот метод описан именно в стандарте HTML. Это маленькое, но полезное улучшение для элементов форм.showPicker() предназначен для программного вызова системных пикеров. Метод доступен у элемента <input> с типами date, month, week, time, datetime-local, color, file, у полей с атрибутом autocomplete, у полей с атрибутом list в сочетании с элементом <datalist> и у <select>. При вызове метода отображается стандартный системный попап для выбора значения, как если бы пользователь нажал на поле самостоятельно.<input type="file">
<button type="button">Upload File</button>
<script>
const button = document.querySelector('button');
const input = document.querySelector('input');
button.addEventListener('click', () => {
try {
input.showPicker();
} catch (error) {
// Обработка ошибок
}
});
</script>
try-catch перехватываются исключения. Метод выбросит исключение NotAllowedError, если пользователь как-либо не взаимодействовал со страницей: скролил, кликал. Это сделано из соображений приватности. Если поле нельзя изменять, например оно в состоянии disabled или readonly, будет выброшено исключение InvalidStateError. Если элемент <select> не отображается на экране, будет выброшено исключение NotSupportedError. И если домен не same origin, то выбрасывается исключение SecurityError.<input type="file">.@font-face {
font-family: 'Roboto Regular';
font-style: normal;
font-weight: 400;
src: local('Roboto'),
url('roboto-regular.eot?#iefix') format('embedded-opentype'),
url('roboto-regular.woff2') format('woff2'),
url('roboto-regular.woff') format('woff'),
url('roboto-regular.ttf') format('truetype'),
url('roboto-regular.svg#Roboto') format('svg');
}fonts с десятом шрифтов разных форматов. Ноги растут из онлайн-генераторов, например, шрифтобелки. На вход поступают шрифты в формате ttf. Далее происходят тонкие настройки, смысл которых понимают только специалисты по шрифтам. На выходе получается архив с готовым CSS и той самой папкой fonts. Это удобно, потому что руками так делать не хочется.local(). Эта функция пытается найти зарегистрированный в операционной системе шрифт и использовать его. На первый взгляд хорошая идея: экономим трафик, не ходим в сеть, переиспользуем ресурсы, быстрее отображаем текст. На практике же с local() много проблем. Шрифт может быть зарегистрирован под другим названием, на устройстве может быть другая версия шрифта, также локальные шрифты используются для фингерпринтинга.woff2. Времена, когда нужны шрифты разных форматов, уже прошли. Все браузеры умеют работать с woff2. На данный момент это самый эффективный формат шрифта для веба, который должен использоваться по умолчанию. Если нужно поддерживать IE, то к woff2 можно добавить woff. Но не нужно генерировать, хранить и подключать svg, eot, ttf и другие менее эффективные и старые форматы.font-family и разные значения font-weight и font-style. Не нужно называть шрифт одного семейства разными именами, например 'Roboto Regular' и 'Roboto Bold'. Назовите оба 'Roboto', а в font-weight и font-style отразите различия. Браузер сам определит, какой шрифт применить, без необходимости каждый раз указывать font-family.@font-face укажите свойство font-display со значением swap, optional или fallback, в зависимости от целей. Это важно для увеличения скорости загрузки, предотвращения сдвигов макета и общего восприятия загрузки сайта. <link>. Сгенерируйте шрифт в Google Fonts, скачайте их локально и взьмите сгенерированные сниппеты CSS.unicode-range. Если язык сайта русский, то нет смысла держать в шрифте многие латинские, японские, китайские и прочие глифы. Для этого шрифт можно разбить на несколько более мелких. В одном оставить кириллицу, цифры и знаки препинания, в другой вынести латиницу и всё остальное. Затем указать это в свойстве unicode-range и браузер скачает только тот шрифт, символы из которого есть на странице. Сам файл при этом будет весить меньше.<style>. Так браузер обнаружит шрифт сразу при получении HTML страницы и не будет ждать загрузки и обработки CSS. Шрифт загрузится и применится раньше. Это позволит избежать вспышек нестилизованного текста (FOUT).<link rel="preload" as="font" format="font/woff2" crossorigin>. Браузер начнёт загрузку шрифта заранее, ещё до того, как фактически обнаружит ссылку. В итоге шрифт частично или полностью будет загружен к моменту его обнаружения. Это также позволяет бороться с FOUT.if-ами и перемещаться по DOM. Вместо этого, при помощи метода querySelector() и сложного селектора, можно сразу получить нужный элемент, который удовлетворяет всем условиям.matches() со сложным селектором и проверять элементы на соответствие.Можно ли в CSS выбрать элемент, внутри которого находятся только кнопки, и этих кнопок две и более?
tablist, внутри которого могут быть только элементы с ролью tab и как минимум два таких.[role="group"]:has(> button:nth-child(2)):not(:has(> :not(button))) {
width: fit-content;
border: 2px solid green;
}<div role="group">
<button type="button">Action 1</button>
<button type="button">Action 2</button>
<button type="button">Action 3</button>
</div>
:has(), :not() и :nth-child(). Что там вообще происходит? Мы говорим:role="group"[role="tablist"]:has(> [role="tab"]:nth-child(2)):not(:has(> :not([role="tab"]))) {
/* стили */
}