---
title: "HTML in CSS: как сократить HTML-код и писать только на CSS"
date: "2024-08-01"
---

<script>
import ArticleTitle from "$lib/components/ArticleTitle.svelte"
</script>

<ArticleTitle metadata={metadata}/>

## О проекте

### Принцип DRY

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

Чтобы предотвратить ошибку, я решил придерживаться главной заповеди чистого кода -- DRY, Don’t Repeat Yourself. Принцип помогает сократить повторяющийся код за счет разделения проекта на мелкие независимые модули. Туда можно с легкостью вносить новые изменения -- другие блоки не пострадают.

DRY замотивировал меня разработать такой проект, в котором принцип осуществлялся на 110%. Изначально, чтобы сверстать страницу, нужно было описать структуру документа в HTML, а потом -- в селекторах на CSS. Приходилось проделывать работу дважды.

Стало интересно, что будет, если поменять структуру документа. Перестать тратить время на написание кода в двух местах и сконцентрироваться только на CSS?

### Работа с фреймворком

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

Перед вами стандартная страница с версткой:

```html
<head>
  <style>
    h1#title {
      font-size: x-large;
      margin-bottom: 32px;
    }

    main#main {
      color: purple;
    }
  </style>
</head>
<body>
  <h1 id="title">Заголовок</h1>

  <main id="main">
    Крутой контент
  </main>
</body>
```

Синьоры и сеньориты среди вас, вероятно, заметили, что лишняя информация находится:
- в HTML -- `h1 id="title"`;
- в CSS -- `h1#title {`;
- в HTML -- `main id="main"`;
- в CSS -- `main#main`.

HTML полностью повторяет код в CSS, поэтому я решил убрать содержимое тега `<body>`. Без него мы не потеряем ничего, кроме контента:

```html
<head>
  <style>
    h1#title {
      font-size: x-large;
      margin-bottom: 32px;
    }

    #title:before {
      content: "Заголовок";
    }

    main#main {
      color: purple;
    }

    #main:before {
      content: "Крутой контент";
    }
  </style>
</head>
<body></body>
```

### Особенности фреймворка

HTML in CSS можно использовать практически на любом коде сайта, но есть несколько оговорок.

Селекторы могут создать только один элемент и не более -- двух одинаковых id не бывает.

```css
#parent > #child {}
```

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

```css
#kopyl-link::before {
  content: "Ссылка на наш сайт";
}
```

Страница может запускаться только в рантайме, поэтому о SEO-оптимизации стоит забыть. Это норма для многих современных фреймворков, если не говорить об их SSR-вариациях.

## Работа с элементами

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

<div class="border-l border-l-slate-400 p-6 bg-slate-900">
У фреймворка есть «козырь в рукаве» -- это селекторы атрибутов. Он предлагает широкий выбор элементов для разработки: от картинок и видео до айфреймов. Мы часто будем использовать его в наших примерах.
</div>

### Ссылки

<div class="grid md:grid-cols-2 gap-4 my-6">
  <div>

    **CSS код**

```css
a#kopyl-link[href="kopyl.dev"] {
  display: block;
}

#kopyl-link::before {
  content: "Ссылка на наш сайт";
}
```

  </div>
  <div>

    **Сгенерированный HTML**

```html
<a
  id="kopyl-link"
  href="kopyl.dev"
></a>
```

  </div>
</div>


А если хотите, чтобы ссылка открывалась в новой вкладке?

<div class="grid md:grid-cols-2 gap-4 my-6">
  <div>

    **CSS код**

```css
a#kopyl-link[href="kopyl.dev"][target="_blank"] {
  display: block;
}
```

  </div>
  <div>

    **Сгенерированный HTML**

```html
<a
  id="kopyl-link"
  href="kopyl.dev"
  target="_blank"
></a>
```

  </div>
</div>

### Вложенность

<div class="grid md:grid-cols-2 gap-4 my-6">
  <div>

    **CSS код**

```css
#parent {
  width: 200px;
  height: 200px;
  background-color: blue;
}

#parent > #child {
  width: 100px;
  height: 100px;
  background-color: green;
}
```

  </div>
  <div>

    **Сгенерированный HTML**

```html
<div id="parent">
  <div id="child"></div>
</div>
```

  </div>
</div>

### Порядок

Используя селекторы псевдоклассов `:nth-child`, `:first-child`, `:last-child`, можно задать порядок элементов.

<div class="grid md:grid-cols-2 gap-4 my-6">
  <div>

    **CSS код**

```css
#parent > #foo:last-child {
  font-size: 10px;
}

#foo::before {
  content: "Я последний";
}

#parent > #bar:first-child {
  font-size: 20px;
}

#bar::before {
  content: "А я первый";
}
```

  </div>
  <div>

    **Сгенерированный HTML**

```html
<div id="parent">
  <div id="bar"></div>
  <div id="foo"></div>
</div>
```

  </div>
</div>

### JavaScript

К сожалению, фреймворк не поддерживает JavaScript, но это не мешает подключить к нему внешний файл -- `main.js`. Да и никто не запретит нам описывать селекторы для тегов `script` и добавлять туда атрибуты.

```css
script#my-script[src="/main.js"] {}
```

В `main.js` можно использовать любой интерактив, который нужен сайту, -- например, обработку событий, клиентский роутер и другие.

## Заключение

Возможно, некоторые уже захотели переписать свой продакшн-сайт на HTML in CSS, но мне жаль вас огорчать -- на самом деле это фреймворк-шутка.

Одним вечером мне стало интересно, как парсится CSS и как выглядит его структура. В процессе изучения пришла в голову идея создать свой фреймворк. Занимает он, кстати, около 120 строк неубористого кода.

<div class="py-4 flex gap-4">
  <a
    href="https://github.com/anatolykopyl/html-in-css"
    target="_blank"
  >
    Репозиторий проекта
  </a>
  <a
    href="https://habr.com/ru/companies/kopyl/articles/832868/"
    target="_blank"
  >
    Обсудить на Хабре
  </a>
</div>

## UPD: 2024-10-02

У проекта появился преемник в лице <a href="https://github.com/Ulyanov-programmer/css2html" target="_blank">css2html</a>.

Автор отнесся к идее несколько серьезнее и превратил проект во что-то, что можно и тайком юзнуть в SSR, вы, например, не можете быть уверенны,
что эта страница не написана на css2html.

Подробности в <a href="https://habr.com/ru/articles/847542/" target="_blank">статье автора проекта</a>.
