Разработка приложений со 100%-й кастомизацией. Customization Driven Development (CDD) / Хабр | Веб-студия Nat.od.ua
Разработка приложений со 100%-й кастомизацией. Customization Driven Development (CDD) / Хабр
В данной статье я хочу поделиться своим опытом разработки интерфейсов с уровнем кастомизации вплоть до 100% (реальные 100%). При этом сохраняется обратная совместимость и возможность апдейтов. Магия? — Нет, это CDD!
Все началось еще в 2018 году в одной крупной международной компании. Меня пригласили в главный офис для объяснения топ руководству как мы будем решать проблему кастомизации нашего продукта, а конкретно UI части. Клиентам необходимо было немного изменить его под себя и кое-что добавить. Нужно было сохранить обратную совместимость, чтобы клиенты могли получать обновления продукта. Тогда я знал только про возможности добавления “дыр” в коде (slots), в которые можно добавить любой функционал. Ну еще и про API, уже для изменения функциональности. Понятно что ни о какой возможности кастомизации на все 100% речи не шло, ведь тогда нужно изменять исходный код, а это само собой потеря обратной совместимости.
Конечно CDD нужен далеко не всем. Эта техника будет крайне полезна при разработке продукта, клиентам которого необходима глубокая кастомизация. Я имею ввиду, не просто поменять логотип и название, а поменять абсолютно все что душе угодно. И при этом не потерять возможность будущих апдейтов продукта.
Как же добиться практически 100%-й кастомизации и без единого разрыва без потери обратной совместимости?
В CDD используется «декларативная кастомизация», т.е. все представление с логикой должны быть вывернуты наружу для возможности полной кастомизации. Если необходимо кастомизировать определенные части довольно сложной компоненты, тогда мы просто отображаем ее более простые внутренние компоненты. Эти компоненты могут быть упакованы в так называемый “черный ящик” с богатым API и “дырами” (slots), либо также отображены еще более простыми компонентами. Представление с логикой любых компонент (кроме примитивных) всегда можно вывернуть наружу, для получения 100% доступа.
И здесь вы можете возразить: “Но как же, ведь когда мы используем внутреннее содержимое, тогда мы теряем возможность апдейтов!”. Нет, это не совсем так, и вот почему:
-
Компонента любой сложности (кроме примитивной) — это всего лишь набор более простых компонент, который всегда есть в свободном доступе и при ее апдейте, мы наглядно видим что и где в этом наборе изменилось и можем очень просто и быстро проапдейтить ее вручную (если это нужно);
-
Сложная компонента состоит из менее сложных компонент, которые мы можем оставить в их стандартном, упакованном виде, если нам не нужна их глубокая кастомизация и естественно будем получать их апдейты автоматически;
Хорошо. А как же этого добиться? Какие шаги?
Сначала нужно разработать самые примитивные компоненты. Они могут, а некоторые из них даже должны иметь по 2 варианта:
-
Стандартный компонент, “черный ящик” с богатым API и “дырами” (slots), удобен в использовании, но имеет ограниченные возможности кастомизации ;
-
Компонент-обертка, расширяет возможности контента, который вы сами помещаете внутрь. Менее удобен в использовании, но имеет гораздо большие возможности кастомизации, вплоть до 100%. Обязательно для стандартных HTML элементов:
Затем, при разработке более сложных компонент, нужно использовать набор из более простых. Как и примитивные компоненты, более сложные компоненты могут иметь 2 версии. Но компонент-обертку можно не создавать, если получится упаковать в стандартный компонент только декларативный шаблон из более простых компонент, без кода для управления им. И затем можно просто использовать внутреннее содержимое, когда нужна кастомизация.
В теории все хорошо. А как дела обстоят на практике?
Я создал технологию https://uiwebkit.com, которая уже делает это на практике. Еще, я сейчас готовлю к публикации проект поменьше и он уже полностью Open Source. Вот там уже наглядно видны все плюсы CDD. Проект будет крайне полезен тем, кто часто работает со сложными, кастомными HTML формами с динамическими полями и валидациями. Хотелось бы рассказать о нем подробнее, но это тема уже другой статьи.
Хотелось бы еще вспомнить нашумевший проект кастомизируемых мобильных телефонов Project Ara. На его примере можно увидеть что в принципе кастомизация нужна не всем и не всегда. Да и переплачивать за возможность кастомизации мало кто хочет. Но те немногие, кому действительно нужна кастомизация, готовы экспериментировать и пробовать разные подходы, чтобы получить именно тот результат, который соответствует именно их ожиданиям.
Буду рад вашим комментариям и мнению на этот счет, либо можете смело писать в личку. Спасибо!
Системный шрифт как проприетарные куки. Необычный метод пометки вашего устройства | Веб-студия Nat.od.ua
Системный шрифт как проприетарные куки. Необычный метод пометки вашего устройства
Предположим, перед разработчиком поставлен такой вопрос — как со стороны веб-сайта определить, что у пользователя установлено конкретное приложение? Вопрос интересный. На него есть несколько способов ответа. Как вам такой вариант — поставить в систему уникальный шрифт при инсталляции программы? Ведь браузер всегда отдаёт по запросу список системных шрифтов. Значит, проблема решена.
Так делают различные программы, хотя это не назовёшь образцом правильного программирования. У метода свои преимущества и недостатки.
Читать дальше →
как автоматически рендерить картинку / Хабр | Веб-студия Nat.od.ua
как автоматически рендерить картинку / Хабр
Всем привет! Меня зовут Николай Каменев, я фронтенд-разработчик в Почтатехе. Мы разрабатываем UI для порталов и приложений Почты России.
Я хочу поделиться коротким гайдом, как автоматически рендерить og:image-изображения для превью сайтов.
Дальше будет небольшая вводная для тех, кто не знаком со сборкой превью по технологии Open Graph. Если вы и так все знаете, переходите сразу в следующий раздел 🙂
О технологии Open Graph
Open Graph позволяет сформировать превью сайта, которое будет отображаться при публикации ссылки на каком-либо ресурсе. Его используют почти все соцсети, мессенджеры и интернет-сервисы.
По стандарту, превью собирается из элементов, помеченных определенными тегами. Они добавляются в тег head. С отображением картинки в превью (ее помечают тегом og:image) бывают проблемы. У каждой площадки свои требования к размеру превью, поэтому исходная картинка может некорректно кадрироваться под нужное окно. Чтобы этого избежать, приходится вручную все правильно настраивать. Моя инструкция поможет сделать это автоматически.
Пример превью в разметке Open Graph
Настраиваем автоматический рендеринг
Я буду генерировать og:image с помощью Next.js. Вы можете использовать любой другой фреймворк, главное, стоит помнить, что изображение формируется на сервере.
0. Инициализируем проект
Создаем приложение командой:
yarn create next-app —typescript
и запускаем его:
yarn devСтартовая страница после генерации Next.js-приложения
Открывается страница приложения — значит, все работает, и можно продолжать.
Для генерации изображений возьмем библиотеку Puppeteer для Node.js. Она дает возможность использовать Headless Chrome Node.js API. С ее помощью мы можем запустить страницу в браузере Chrome на беке, сделать скриншот и отправить клиенту как og:image.
Меньше слов, больше дела. Устанавливаем Puppeteer:
yarn add puppeteer1. Пишем функцию — обработчик запроса
Переходим в папку /api, создаем файл og-image.ts и пишем функцию OGImage, которая принимает request и отдает response (подробнее про Next.js API — в документации).
// pages/api/og-image.ts
import {NextApiRequest, NextApiResponse} from «next»;
export default async function OGImage(req: NextApiRequest, res: NextApiResponse) {
try {
} catch (e) {
}
}2. Формируем интерфейс запроса данных для картинки
Теперь нужно решить, каким образом будем передавать в запросе данные для картинки. Я выбрал метод query. Он позволяет использовать простой запрос GET с параметрами. Пример запроса: https://example.com/api/og-image?title=”Test”
Определяем, что мы ожидаем от клиента title и description, создаем файл types.ts в папке _lib и описываем интерфейс request.
// pages/api/_lib/types.ts
export interface ParsedRequest {
title?: string;
desc?: string;
}3. Пишем функцию для получения параметров запроса
Создаем parser.ts в папке _lib. Функция будет обрабатывать запрос и возвращать заголовок и описание.
// pages/api/_lib/parser.ts
import {NextApiRequest} from «next»;
import {ParsedRequest} from «./types»;
export function parseRequest(req: NextApiRequest) {
const { title, desc } = req.query as ParsedRequest;
return {
title,
desc,
};
}4. Делаем шаблон разметки картинки
Параметры получили, теперь самое время заняться оформлением картинки. Для упрощения стилизации я буду использовать библиотеку готовых компонентов MUI.
Создаем React-компонент (можно использовать чистый html):
// pages/api/_lib/template.tsx
export const OGImage: FC
return (
{title}
{desc}
)
}
и функцию для рендеринга React-компонента в html-код:
// pages/api/_lib/template.tsx
export function getHtml(parsedReq: ParsedRequest) {
const { title, desc } = parsedReq;
return renderToString(
}
Осталось отрендерить эту страницу и сделать скриншот. Снова переходим в папку _lib и создаем файл render.ts. В нем сделаем функцию для генерации браузерной страницы и сохранения скриншота. Функция принимает html-код, который мы получили выше.
// pages/api/_lib/render.ts
import core from ‘puppeteer’;
export async function getScreenshot(html: string) {
const browser = await core.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1200, height: 630, deviceScaleFactor: 2 });
await page.setContent(html);
return await page.screenshot({ type: ‘png’ });
}
Ширину и высоту я указал оптимальную для разных платформ, deviceScaleFactor позволяет увеличить изображение в два раза для устройств с высоким разрешением экрана. Тип скриншота можно выбрать любой (png, jpeg, webp).
5. Собираем превью// pages/api/og-image.ts
import {NextApiRequest, NextApiResponse} from «next»;
import {parseRequest} from «./_lib/parser»;
import {getHtml} from «./_lib/template»;
import {getScreenshot} from «./_lib/render»;
export default async function OGImage(req: NextApiRequest, res: NextApiResponse) {
try {
const parsedReq = parseRequest(req);
const html = getHtml(parsedReq);
const file = await getScreenshot(html);
res.statusCode = 200;
res.setHeader(‘Content-Type’, `image/png`);
res.setHeader(‘Cache-Control’, `public, immutable, no-transform, s-maxage=31536000, max-age=31536000`);
res.end(file);
} catch (e) {
res.statusCode = 500;
res.setHeader(‘Content-Type’, ‘text/html’);
res.end(‘
Internal Error
Sorry, there was a problem
‘);
console.error(e);
}
}
Переходим по запросу: http://localhost:3000/api/og-image?title=Заголовок&desc=Тестируем%20динамическое%20превью
Вуаля! У нас появляется картинка.
Превью, которое мы получили, используя шаблон из четвертого шага6. Добавляем тег в head
И последний шаг:
Заключение
Мы получили быстрое и простое решение для динамического рендеринга превью. Это базовый функционал, в котором используются только текстовые переменные. К нему можно добавить и картинки — достаточно сделать новый шаблон.
Полный пример проекта, который мы собрали в этой статье, вы можете найти в GitHub-репозитории.
Топ-25 бесплатных курсов веб-разработчика 2022 года / Хабр | Веб-студия Nat.od.ua
Топ-25 бесплатных курсов веб-разработчика 2022 года / Хабр
Подготовили для вас подборку бесплатных курсов и тренажеров обучения для веб-разработке с нуля.
Также на нашем сайте есть раздел со всеми платными курсами по web-разработке и отзывами о них — https://katalog-kursov.ru/courses/kursy_po_web_razrabotke/
Для начинающих, не надо проходить сразу все курсы) Выберете внимательно какой вам больше подходит и начните его проходить.
Тренажеры
-
Тренажер HTML для начинающих
Формат: обучающий онлайн-тренажер. Состоит из 41 урока. -
Тренажер CSS для начинающих
Формат: обучающий онлайн-тренажер. Состоит из 33 уроков. -
Тренажер W3Schools
Формат: обучающий онлайн-тренажер. -
Тренажер BitDegree.org
Формат: обучающий онлайн-тренажер.
Бесплатные курсы от школ
-
«Основы HTML, CSS, JS: бесплатный вводный курс» от ЯндексаПрактикум
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 83 уроков. -
«Веб-разработка для начинающих: HTML и CSS» от Stepik
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 49 уроков. -
«Основы языка PHP» от Хекслет
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 41 урока. -
«Карьерный гид: Fullstack-разработчик» от SkillFactory
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 30 уроков. -
«Создавай сайты и зарабатывай на них» от Артема Башлыкова
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 25 уроков. -
«Создание динамического веб-сайта» от ItProger
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 22 уроков. -
«Уроки HTML5» от ItProger
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 18 уроков. -
«Основы вёрстки сайта» от Нетологии
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 16 уроков. -
«Создание блога на WordPress» от GeekBrains
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 13 уроков. -
«Ключевые аспекты веб-разработки на PHP» от Хекслет
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 13 уроков. -
«Уроки CSS» от ItProger
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 10 уроков. -
«Java. Быстрый старт» от GeekBrains
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 9 уроков. -
«Веб-программирование» от SkillBox
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 8 уроков. -
«Введение в веб-разработку» от Hexlet
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 8 уроков. -
«Веб-верстальщик: начало» от WayUp
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 7 уроков. -
«Создание Landing Page» от Tilda Publishing
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 5 уроков. -
«Знакомство с HTML и CSS» от HTML академии
Формат: видеоуроки в записи и задания с самопроверкой. Состоит из 5 уроков.
Бесплатные курсы с Youtube
-
Веб-разработчик 10.0
Формат: видеоуроки с Youtube. Состоит из 32 уроков. -
Создаём сайт с нуля на CMS Joomla 3
Формат: видеоуроки с Youtube. Состоит из 32 уроков. -
Создание сайта на Django
Формат: видеоуроки с Youtube. Состоит из 14 уроков. -
Изучение ASP.NET Core MVC. Создание сайтов на C#
Формат: видеоуроки с Youtube. Состоит из 11 уроков. -
Основы веб-разработки
Формат: видеоуроки с Youtube. Состоит из 8 уроков. -
Web разработка
Формат: видеоуроки с Youtube. Состоит из 7 уроков. -
Как создать сайт и заработать деньги. Создание сайта с нуля
Формат: видеоуроки с Youtube. Состоит из 5 уроков.
Как выбрать курс?
Большое количество бесплатных курсов это хорошо, но это увеличивает сложность выбора. Давайте разберем как выбрать курс по веб-разработке.
Бесплатные курсы от больших школ, например, Skillbox или Geekbrains, первыми привлекают внимание. Но они, чаще всего, используются как рекламный инструмент. В них расскажут совсем базовые вещи и большую часть времени будут расписывать про их платные продукты. Так что подобные курсы подойдут, если вы хотите познакомиться в целом с данным направлением и узнать больше о школе.
Также в списке есть курсы по web-разработке от школы типа Stepik. В таких школах можно получить реально бесплатный курс, который будет вести тебя по всем основам нужного направления. Это уже более полноценные курсы. Но стоит понимать, что там курсы в записи. У вас не будут проверять домашние задания и давать советы. Но задания в таких курсах рассчитаны так, чтобы вы сами справлялись.
Есть курсы с Youtube. Главный их минус, как и в прошлом пункте, вы будете смотреть уроки и учится, но у вас не будет наставника, который будет вам помогать в нужные моменты. Важно при выборе курса с Youtube смотреть на актуальность и качество курса. Посмотрите на дату выкладывания видео и почитайте комментарии под первыми уроками.
Также бывают бесплатные обучающие тренажеры. Это крутой вид обучения, т.к. тут ты не просто слушаешь уроки, а сразу практикуешься. Бывают тренажеры, которые дают вначале теорию, а потом ты закрепляешь практикой, это самое удобное. На наш взгляд, это наиболее оптимальный метод обучения. Но есть минус: как правило, теории в них слишком мало. И параллельно тренажеру, надо проходить еще какой-то теоретический курс.
Добавление масштабирования при ширине экрана менее чем body min-width в Firefox и Safari / Хабр | Веб-студия Nat.od.ua
Добавление масштабирования при ширине экрана менее чем body min-width в Firefox и Safari / Хабр
Устройства пользователей в наши дни отличаются широким разнообразием: телевизоры, смартфоны, планшеты и даже часы — с каждого из устройств пользователь может захотеть выйти в сеть. А если добавить сюда разные браузеры, которые можно установить на устройство, то получатся тысячи комбинаций того, как можно попасть на ваш сайт.
Вот и я, в ходе работы над своим сайтом портфолио, тестировал его в разных браузерах и наткнулся на проблему.
Проблема
При указании свойства min-width: 320px для тега body в Firefox, контент, при достижении минимальной ширины, не начинает пропорционально уменьшаться как в Chrome (рис 1), а просто выходит за экран. (рис 2)
Рисунок. 1
Демонстрация правильной работы min-width: 320 для body в Chrome 105
(После 320px начинает пропорционально уменьшаться)Рисунок. 2
Демонстрация неправильной работы min-width: 320px для body в Firefox 103 (После 320px появляется горизонтальный скролл)Зачем решать эту проблему?
Допустим, у меня сломался основной смартфон, а в запасе только Samsung Galaxy Mini с шириной экрана в 240px и с браузером Firefox. На таких устройствах, треть контента сайта будет выходить за viewport, что приведет к появлению горизонтального скролла, а это не удобно.
Также поддержка ширины в менее чем 320px, может быть полезна для браузеров в которых есть функция боковых веб-панелей (например Vivaldi).
Поддержка min-width для body в других браузерах
В ходе тестирования в других браузерах, оказалось, что Safari (проверялось на Safari 15) также имеет данную проблему. (рис 3)
Рисунок. 3
Демонстрация работы неправильной работы min-width: 320px для body в Safari 15 (После 320px появляется горизонтальный скролл)
В принципе, свойство min-width для body без проблем работает на всех браузерах с движком Chromium. По крайней мере, кроме Chrome, все работает как положено в последних версиях Edge (105), Vivaldi (5.4), Opera (90.0.4480) и Yandex (102).
Решение
Сначала, я попробовал решить данную проблему путем добавления свойства min-width, не только к тегу body, но и к тегу html и обертке контента div class=»wrapper», увы, данный способ не сработал.
В связи с этим, я написал функцию, которая уменьшает контент при достижении определенной ширины экрана. Она сравнивает ширину контента страницы с доступной шириной окна (viewport), а затем уменьшает страницу так, чтобы эти значения оставались равны.
При этом, масштабирование страницы является не только визуальным как в случае с transform: scale(), но и влияет на размеры. Если не влиять на ширину, контент будет выглядеть хорошо, но горизонтальный скролл останется. (рис 4)
Рисунок. 4
Демонстрация того, что будет происходить в старых версиях Firefox, если использовать transform: scale() не меняя размеры (Контент выглядит хорошо, но скролл остается)
Да, для масштабирования с изменением размера существует CSS свойство zoom, которое не только масштабирует элемент как свойство transform: scale(), но и пропорционально меняет его размеры, влияя на окружение. К сожалению, в Firefox свойство zoom не поддерживается (Can I Use Zoom). И именно поэтому для масштабирования применяется связка свойств transform: scale() и width.
CSS свойства применяются к тегу html, так как на теге body установлено свойство min-width и свойство width не будет работать.
Ниже приведен пример работы функции. (рис 5)
Рисунок. 5
Демонстрация правильной работы min-width: 320px для body в Firefox с созданной функцией (Контент масштабируется, скролла нет)О том как использовать функцию
Для начала, зайдите на репозиторий GitHub: https://github.com/fazdendev/adaptive-body-min-width
Затем, скопируйте код из function.js к себе в проект и вызовите функцию.
adaptiveSizePageScaleInit(300)
В качестве аргумента передайте в неё ширину окна браузера, при котором функция должна запускаться (по умолчанию 320). Очень важно, чтобы значение body min-width было равно значению переданному в функцию.
Если вы хотите, чтобы функция запускалась только в определенных браузерах уберите вызов функции adaptiveSizePageScaleInit()и скопируйте функцию вызова кода в определённых браузерах startOnSpecificBrowserInit()
Замените строку «НЕОБХОДИМЫЙБРАУЗЕР» из условия в функции startOnSpecificBrowserInit() нужным вариантом из списка: «other», «msEdge», «chrEdge», «opera«, «сhrome», «ie», «firefox», «safari».
Условие, в котором нужно менять строку:
if (browser == «НЕОБХОДИМЫЙБРАУЗЕР») {adaptiveSizePageScaleInit()}
Заключение
Я надеюсь, что эта статья была вам полезна!
В будущем, я добавлю функции возможность брать значение body min-width из CSS, так чтобы вам не пришлось задавать переменную вручную.
Если у вас есть какие вопросы или предложения по решению данной проблемы, я буду рад обратной связи.
Ну а на этом все, хорошего вам дня!)
важен ли порядок названий классов CSS в атрибуте «class» HTML-элементов / Хабр | Веб-студия Nat.od.ua
важен ли порядок названий классов CSS в атрибуте «class» HTML-элементов / Хабр
У HTML-элементов на HTML-странице может быть необязательный глобальный атрибут class. Например:
Здесь у HTML-элемента div есть интересующий нас атрибут class.
С точки зрения стандарта языка HTML
По действующему стандарту языка HTML атрибут class HTML-элементов должен содержать значение, состоящее из набора (множества) названий (токенов) классов CSS, разделенных пробельными символами (символ пробела, символ горизонтальной табуляции, символы новой строки). В примере выше атрибут class содержит значение-строку имя-класса1 имя-класса2 имя-класса3, представляющее собой набор из трех названий классов CSS, разделенных символом пробела.
Понятие, о котором тут идет речь — набор из слов (токенов), разделенных пробельными символами (по-английски «set of space-separated tokens»). Само это понятие определено в стандарте языка HTML отдельно от определения атрибута class.
В определении понятия «set of space-separated tokens» сказано, что это строка, содержащая ноль или более слов (токенов), разделенных пробельными символами. Из этого я сделал вывод, что атрибут class по действующему стандарту HTML может не содержать ничего (содержать пустую строку). Также не будет нарушением действующего стандарта HTML, если этот атрибут будет содержать только пробельные символы (символ пробела, символ горизонтальной табуляции, символы новой строки).
Действующий стандарт HTML вообще практически не накладывает на набор названий классов CSS в атрибуте class HTML-элементов каких-либо ограничений. Не накладывается ограничение на дублирование названий классов CSS внутри атрибута class. Не накладывается каких-либо ограничений, касающихся порядка перечисления названий классов CSS внутри атрибута class.
То есть с точки зрения действующего стандарта HTML (в отличие от стандарта CSS, о чем речь пойдет далее) название класса, перечисленное в наборе названий классов внутри атрибута class HTML-элемента раньше (левее, выше), ничем не отличается от названия класса, перечисленного в том же наборе названий классов внутри атрибута class HTML-элемента позже (правее, ниже).
В примере выше с точки зрения действующего стандарта HTML названия классов имя-класса1, имя-класса2 и имя-класса3 в наборе названий имя-класса1 имя-класса2 имя-класса3 полностью равноправны, несмотря на то, что, к примеру, название имя-класса1 перечислено раньше (левее), чем имя-класса2 или имя-класса3. То же самое касается названия имя-класса2 по сравнению с названием имя-класса3.
Во что это выливается на практике?
Рассмотрим такой код на языке HTML (многоточием заменен неинтересный для предмета этой статьи код):
…
…
Какой-то текст1.
Какой-то текст2.
…
В теле этой HTML-страницы есть два параграфа (HTML-элемент p). Каждый из этих параграфов содержит атрибут class с набором из одних и тех же трех названий классов CSS, только перечисленных в разном порядке.
Описание стилей в классе имя-класса3 не конфликтует с другими классами. А вот описания стилей в классах имя-класса1 и имя-класса2 конфликтуют друг с другом (приписывают разные значения одному и тому же свойству HTML-элемента).
В итоге при любой перестановке названий классов CSS в атрибуте class HTML-элементов p браузер отобразит параграфы одинаково, в данном случае — с синей границей и текстом красного цвета. Это подтверждает наши выводы, сделанные выше из определений действующего стандарта HTML.
Почему же в данном случае в конфликте описаний стилей в классах имя-класса1 и имя-класса2 «победил» класс имя-класса2 (текст в параграфах отразился красным цветом)? Потому что при определении классов CSS внутри HTML-элемента style класс имя-класса2 описан позже (ниже), чем класс имя-класса1. Внутри HTML-элемента style действуют правила (стандарт) языка CSS. Это действие того самого «каскада», давшего первую букву аббревиатуре CSS (Cascading Style Sheets). Если менять местами определения классов CSS внутри HTML-элемента style (или внутри файла с кодом на языке CSS, если определения стилей вынесены в отдельный файл или файлы), то отображение HTML-страницы в браузере будет изменяться.
Влияние правил языка CSS
Всегда ли порядок названий классов в атрибуте «class» HTML-элемента не влияет на отображение HTML-страницы?
С учетом вышеизложенного хочется ответить на этот вопрос утвердительно, но утвердительный ответ тут будет неправильным.
Дело в том, что в языке CSS можно определить селектор (отборщик) HTML-элементов так, что отбор HTML-элементов селектором будет зависеть от порядка перечисления названий классов CSS в атрибуте class HTML-элементов. Это сделает порядок перечисления названий классов в атрибуте class HTML-элементов значимым для отображения HTML-страницы в браузере.
Это не будет противоречить вышеописанным выводам, сделанным из определений в стандарте языка HTML, потому что в данном случае это будет действие стандарта CSS.
В качестве примера рассмотрим такой код на языке HTML:
…
…
Какой-то текст1.
Какой-то текст2.
…
Это тот же код HTML, что и в первом примере, только здесь изменены два первых селектора внутри HTML-элемента style. Даже описания стилей остались нетронутыми. Однако, теперь браузер отображает в первом параграфе текст зеленым цветом, а во втором параграфе — красным цветом.
В этом примере порядок названий классов внутри атрибута class HTML-элементов стал значимым для отображения HTML-страницы в браузере, но это действие не правил языка HTML, а правил языка CSS.
Заключение
Итак, окончательный ответ на вопрос, заданный в заголовке этой статьи, должен звучать следующим образом.
Порядок названий классов CSS в атрибуте class HTML-элементов на HTML-странице может влиять (может быть важным) на отображение этой HTML-страницы в браузере. Но следует понимать, что это влияние определяется не правилами (стандартом) языка HTML, а тем, как описаны стили для данной HTML-страницы с помощью языка CSS (они могут быть описаны в разных местах — внутри HTML-элемента style, внутри внешнего файла (нескольких файлов) и так далее).
Кто-нибудь, объясните мне прелесть tailwind / Хабр | Веб-студия Nat.od.ua
Кто-нибудь, объясните мне прелесть tailwind / Хабр
Я честно пытаюсь понять, читаю официальную документацию и в преимуществах вижу полную ересь:
-
You aren’t wasting energy inventing class names. No more adding silly class names like sidebar-inner-wrapper just to be able to style something, and no more agonizing over the perfect abstract name for something that’s really just a flex container.
Возможно, но, во-первых, осмысленные имена классов дробят полотно разметки на блоки и элементы, во-вторых, разве мне не придется тратить время на поиск имени класса tailwind, соответствующему css-правилу?
-
Your CSS stops growing. Using a traditional approach, your CSS files get bigger every time you add a new feature. With utilities, everything is reusable so you rarely need to write new CSS.
Но ведь CSS tailwind’а уже распух описанием все возможных комбинаций, только посмотрите на это:
Кусок CSS со страницы https://tailwindcss.com/docs/utility-first
Making changes feels safer. CSS is global and you never know what you’re breaking when you make a change
Это просто ложь, даже webpack соберет стили индивидуально для каждого компонента, добавив уникальный аттрибут (







