Просте розтягнення на всю ширину екрана *:not()

493

Від автора: наприклад, ви робите макет для поста в блозі. Ви написали контент в CMS через WYSIWYG-редактор і вивели його на сторінку. Потім ви відкриваєте сторінку на мобільному пристрої і бачите, що параграфи розтягнуті на всю ширину. Трохи незручно. Ви додаєте поле зліва і справа, наприклад, з допомогою div.container.

Це буде працювати рівно до тих пір, поки клієнт не захочеться розтягнути зображення і відео на всю ширину. Тепер ваш універсальний спосіб з padding не працює. У вас є кілька варіантів:

Прописати

в розмітці в WYSIWYG. Хай допоможе вам Бог, якщо ви підете таким шляхом.

Розділити $post->content на окремі частини в CMS. Якщо вибрати цей спосіб, потрібно буде написати front-end і back-end логіку для візуалізації всіх частин контенту (частини в контейнері і без). Цей спосіб довше обслуговувати. Ви розбили контент в базі даних тільки для візуальної стилізації, що не можна назвати хорошим поділом завдань.

Можна обійтися без контейнера. Однак доведеться явно прописати padding для всіх дочірніх елементів крім зображень. Якщо піти цим шляхом, то CSS буде приблизно таким:

.post > h1,
.post > h2,
.post > h3,
/* Repeat for every block level element in the HTML */
.post > p {
margin-left: auto;
margin-right: auto;
max-width: 50rem;
padding-left: 5%;
padding-right: 5%;
}

Це спрацює, але завжди буде щось, що ви не врахували. Одні зображення будуть розтягуватися на всю ширину, інші – ні. Всі iframe’и або тільки YouTube і Vimeo? Ви керуєте і вхождениями і винятками з правила. Кілька запитів клієнта, і ваш CSS код став просто величезним.

Давайте спробуємо *:not()

Я лінивий, тому подумав, як написати весь цей CSS код набагато простіше. І я знайшов просте і елегантне рішення з допомогою селектора :not() специфікації CSS Level 3.

.post > *:not( img ):not( video ) {
margin-left: auto;
margin-right: auto;
max-width: 50rem;
padding-left: 5%;
padding-right: 5%;
}

Тепер я керую тільки винятками. Цей трюк я використовую в своєму блозі, щоб вирватися з нудного, але надійною «труби контенту». Спосіб можна перевести на безліч елементів:

.post > *:not(img):not(video):not(table):not(iframe[src*=”codepen”]) { /* … */ }

Я просто додаю ті елементи в список, які необхідно висмикнути з контейнера і збільшити. Спосіб :not() досить універсальний.

Кольорові фонові рівні

Цю техніку можна перенести на теги section і div, щоб задавати їм різні кольорові фони (як на маркетингових сайтах), після чого вони переробляються таким чином, що цей div отримує стилі підробленого контейнера.

.post > *:not( .colored-bg ),
.colored-bg > * {
margin-left: auto;
margin-right: auto;
max-width: 50rem;
padding-left: 5%;
padding-right: 5%;
}
.colored-bg {
background: lightgray;
padding-top: 5%;
padding-bottom: 5%;
}

Демо: макет поста в блозі

Щоб перевірити теорію, я створив стандартний макет поста в блозі, в якому приблизно 70 рядків CSS. Мені цього цілком достатньо.

Мені подобається, до чого все йде

Буду чесний, у способу є деякі обмеження. Вибір з допомогою селектора * — досить дороге задоволення, якщо сторінка величезна. Ви пишіть селектори зліва направо, але CSS оцінює їх справа наліво. Перезаписати селектор :not() досить складно (див. blockquote в демо). Обчислення при зміні розмірів можуть дорого обійтися браузерам.

Напевно, я буду користуватися цим методом. Мені подобається, що я не відкриваю і не закриваю контейнери. Мені подобається, що я можу писати код прямо. Мені подобається, що це відносно дешевий і легкий спосіб вирватися за межі нудною труби контенту, навіть якщо це мало що змінює.

Зараз я працюю над парою проектів, де блоки-обгортки div реально вносять плутанину і роблять код менш гнучким. Ми з Chris Coyier навіть обговорювали це питання в останньому випуску подкасту rapidfire на Shop Talk Show. Схоже, це відмінний спосіб.