← HTML & CSS/Правила хорошего HTML#15 из 383← ПредыдущийСледующий →+15 XP
Полезно по теме:Гайд: старт в frontendПрактика: DOM и событияТермин: DOMМаршрут: старт с нуля

Правила хорошего HTML

Ты уже знаешь все основные теги и концепции HTML. Теперь поговорим о том, что отличает профессионала от новичка: правильная структура, именование, форматирование и валидация. Хороший HTML — это не просто «работает», это «работает, понятно и поддерживается».

1. Валидная структура документа

Каждый HTML-документ должен начинаться с корректной базовой структуры:

<!DOCTYPE html>
<html lang="ru">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Описательный заголовок страницы</title>
  </head>
  <body>
    <!-- Контент -->
  </body>
</html>

2. Правильная вложенность тегов

<!-- ПЛОХО: нарушена вложенность -->
<p>Текст <strong>жирный <em>жирный-курсив</strong> курсив</em></p>

<!-- ХОРОШО: теги закрываются в обратном порядке -->
<p>Текст <strong>жирный <em>жирный-курсив</em></strong> <em>курсив</em></p>

HTML — это дерево. Каждый открытый тег должен быть закрыт до того, как закроется его родитель.

3. Строчные буквы везде

<!-- ПЛОХО: заглавные теги -->
<DIV CLASS="header">
  <H1>Заголовок</H1>
</DIV>

<!-- ХОРОШО: строчные теги -->
<div class="header">
  <h1>Заголовок</h1>
</div>

HTML нечувствителен к регистру, но конвенция — всегда строчные.

4. Самозакрывающиеся теги

Теги без содержимого (void elements) должны правильно закрываться:

<!-- В HTML5 оба варианта корректны, но <tag /> предпочтительнее для JSX -->
<img src="photo.jpg" alt="Фото" />
<br />
<hr />
<input type="text" />
<meta charset="UTF-8" />

5. Атрибуты в двойных кавычках

<!-- ПЛОХО: без кавычек или одинарные кавычки -->
<img src=photo.jpg alt=Фото />
<a href='https://example.com'>Ссылка</a>

<!-- ХОРОШО: двойные кавычки -->
<img src="photo.jpg" alt="Фото" />
<a href="https://example.com">Ссылка</a>

6. Осмысленные имена классов и id

<!-- ПЛОХО: непонятные имена -->
<div class="d1 red big">...</div>
<div id="x">...</div>

<!-- ХОРОШО: имена описывают назначение, не внешний вид -->
<div class="product-card featured">...</div>
<div id="checkout-modal">...</div>

Используй kebab-case для классов и id. Называй по назначению, а не по виду: не red-text, а error-message.

7. Отступы и форматирование

<!-- ПЛОХО: всё в одну строку -->
<div class="card"><img src="prod.jpg" alt="Товар" /><h3>Nike Air Max</h3><p class="price">7 990 ₽</p><button>Купить</button></div>

<!-- ХОРОШО: отступы 2 пробела, каждый элемент на своей строке -->
<div class="product-card">
  <img src="product.jpg" alt="Кроссовки Nike Air Max 90" />
  <h3 class="product-title">Nike Air Max 90</h3>
  <p class="product-price">7 990 ₽</p>
  <button class="btn btn-primary" type="button">Купить</button>
</div>

8. Комментарии — умеренно

<!-- Начало секции каталога -->
<section class="catalog">
  ...
</section>
<!-- /Конец секции каталога -->

<!-- Временно скрыто до запуска -->
<!-- <div class="promo-banner">...</div> -->

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

9. Не смешивать семантику и представление

<!-- ПЛОХО: используем теги для стилизации, не для семантики -->
<b>Важный текст</b>   <!-- b = просто жирный -->
<i>Иностранное слово</i>  <!-- i = просто курсив -->
<br /><br />  <!-- Отступы через br — нет! -->

<!-- ХОРОШО: теги по смыслу, отступы через CSS -->
<strong>Важный текст</strong>  <!-- strong = важность -->
<em>Иностранное слово</em>    <!-- em = акцент -->

10. Валидация — проверяй результат

Инструмент: validator.w3.org — официальный валидатор W3C. Вставь URL или HTML-код и получи список ошибок. В реальных проектах валидацию интегрируют в CI/CD.

Чеклист перед сдачей HTML

  • [ ] DOCTYPE есть
  • [ ] lang задан у html
  • [ ] charset UTF-8 первым в head
  • [ ] viewport для мобильных
  • [ ] title уникальный, до 60 символов
  • [ ] Все img имеют alt
  • [ ] Все input имеют label
  • [ ] Один h1 на странице
  • [ ] Заголовки в правильной иерархии
  • [ ] Теги строчные
  • [ ] Атрибуты в двойных кавычках
  • [ ] Корректная вложенность
  • В реальных проектах

    В командах используют линтеры для HTML: HTMLHint, html-validate. Prettier форматирует HTML автоматически. Обзор кода (code review) всегда включает проверку HTML-качества. Хороший HTML — это уважение к коллегам, поисковикам и пользователям.

    Примеры

    Генерация и форматирование валидного HTML документа

    // Генерируем корректный HTML-документ программно
    function createHTMLDocument(config) {
      const lines = []
    
      lines.push('<!DOCTYPE html>')
      lines.push('<html lang="' + (config.lang || 'ru') + '">')
      lines.push('  <head>')
      lines.push('    <meta charset="UTF-8" />')
      lines.push('    <meta name="viewport" content="width=device-width, initial-scale=1.0" />')
      lines.push('    <title>' + config.title + '</title>')
      if (config.description) {
        lines.push('    <meta name="description" content="' + config.description + '" />')
      }
      lines.push('  </head>')
      lines.push('  <body>')
      lines.push('    <header>')
      lines.push('      <nav>')
      lines.push('        <ul>')
      config.navLinks.forEach(link => {
        lines.push('          <li><a href="' + link.href + '">' + link.text + '</a></li>')
      })
      lines.push('        </ul>')
      lines.push('      </nav>')
      lines.push('    </header>')
      lines.push('    <main>')
      lines.push('      <h1>' + config.h1 + '</h1>')
      lines.push('    </main>')
      lines.push('    <footer>')
      lines.push('      <p>' + config.footer + '</p>')
      lines.push('    </footer>')
      lines.push('  </body>')
      lines.push('</html>')
    
      return lines
    }
    
    const html = createHTMLDocument({
      lang: 'ru',
      title: 'Sneaker Shop — Кроссовки онлайн',
      description: 'Лучший магазин кроссовок',
      h1: 'Каталог кроссовок',
      navLinks: [
        { href: '/', text: 'Главная' },
        { href: '/catalog', text: 'Каталог' },
        { href: '/about', text: 'О нас' },
      ],
      footer: '© 2024 Sneaker Shop',
    })
    
    html.forEach(line => console.log(line))
    console.log('Строк в документе:', html.length)

    HTML-линтер — проверка типичных ошибок

    // Простой HTML-линтер (проверяем правила через строки)
    function lintHTML(htmlString) {
      const errors = []
      const warnings = []
    
      // Проверка DOCTYPE
      if (!htmlString.includes('<!DOCTYPE html>')) {
        errors.push('Нет <!DOCTYPE html>')
      }
    
      // Проверка lang
      if (!htmlString.includes('lang=')) {
        errors.push('Нет атрибута lang у <html>')
      }
    
      // Проверка charset
      if (!htmlString.includes('charset=')) {
        errors.push('Нет meta charset')
      }
    
      // Проверка title
      if (!htmlString.includes('<title>')) {
        errors.push('Нет тега <title>')
      }
    
      // Проверка заглавных тегов
      if (/<[A-Z]/.test(htmlString)) {
        warnings.push('Найдены теги в верхнем регистре — используй строчные')
      }
    
      // Проверка атрибутов без кавычек
      if (/=w+[s>]/.test(htmlString.replace(/="[^"]*"/g, ''))) {
        warnings.push('Возможны атрибуты без кавычек')
      }
    
      // Проверка img без alt
      const imgWithoutAlt = (htmlString.match(/<img(?![^>]*alt=)[^>]*>/g) || []).length
      if (imgWithoutAlt > 0) {
        errors.push('Найдено ' + imgWithoutAlt + ' тег(ов) img без alt')
      }
    
      return { errors, warnings }
    }
    
    const badHTML = `<HTML>
      <head>
        <title>Мой сайт</title>
      </head>
      <body>
        <IMG src="photo.jpg" />
        <div class=wrapper>Контент</div>
      </body>
    </HTML>`
    
    const result = lintHTML(badHTML)
    console.log('Ошибок:', result.errors.length)
    result.errors.forEach(e => console.log('ОШИБКА: ' + e))
    console.log('Предупреждений:', result.warnings.length)
    result.warnings.forEach(w => console.log('ПРЕДУПРЕЖДЕНИЕ: ' + w))

    Правила хорошего HTML

    Ты уже знаешь все основные теги и концепции HTML. Теперь поговорим о том, что отличает профессионала от новичка: правильная структура, именование, форматирование и валидация. Хороший HTML — это не просто «работает», это «работает, понятно и поддерживается».

    1. Валидная структура документа

    Каждый HTML-документ должен начинаться с корректной базовой структуры:

    <!DOCTYPE html>
    <html lang="ru">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Описательный заголовок страницы</title>
      </head>
      <body>
        <!-- Контент -->
      </body>
    </html>

    2. Правильная вложенность тегов

    <!-- ПЛОХО: нарушена вложенность -->
    <p>Текст <strong>жирный <em>жирный-курсив</strong> курсив</em></p>
    
    <!-- ХОРОШО: теги закрываются в обратном порядке -->
    <p>Текст <strong>жирный <em>жирный-курсив</em></strong> <em>курсив</em></p>

    HTML — это дерево. Каждый открытый тег должен быть закрыт до того, как закроется его родитель.

    3. Строчные буквы везде

    <!-- ПЛОХО: заглавные теги -->
    <DIV CLASS="header">
      <H1>Заголовок</H1>
    </DIV>
    
    <!-- ХОРОШО: строчные теги -->
    <div class="header">
      <h1>Заголовок</h1>
    </div>

    HTML нечувствителен к регистру, но конвенция — всегда строчные.

    4. Самозакрывающиеся теги

    Теги без содержимого (void elements) должны правильно закрываться:

    <!-- В HTML5 оба варианта корректны, но <tag /> предпочтительнее для JSX -->
    <img src="photo.jpg" alt="Фото" />
    <br />
    <hr />
    <input type="text" />
    <meta charset="UTF-8" />

    5. Атрибуты в двойных кавычках

    <!-- ПЛОХО: без кавычек или одинарные кавычки -->
    <img src=photo.jpg alt=Фото />
    <a href='https://example.com'>Ссылка</a>
    
    <!-- ХОРОШО: двойные кавычки -->
    <img src="photo.jpg" alt="Фото" />
    <a href="https://example.com">Ссылка</a>

    6. Осмысленные имена классов и id

    <!-- ПЛОХО: непонятные имена -->
    <div class="d1 red big">...</div>
    <div id="x">...</div>
    
    <!-- ХОРОШО: имена описывают назначение, не внешний вид -->
    <div class="product-card featured">...</div>
    <div id="checkout-modal">...</div>

    Используй kebab-case для классов и id. Называй по назначению, а не по виду: не red-text, а error-message.

    7. Отступы и форматирование

    <!-- ПЛОХО: всё в одну строку -->
    <div class="card"><img src="prod.jpg" alt="Товар" /><h3>Nike Air Max</h3><p class="price">7 990 ₽</p><button>Купить</button></div>
    
    <!-- ХОРОШО: отступы 2 пробела, каждый элемент на своей строке -->
    <div class="product-card">
      <img src="product.jpg" alt="Кроссовки Nike Air Max 90" />
      <h3 class="product-title">Nike Air Max 90</h3>
      <p class="product-price">7 990 ₽</p>
      <button class="btn btn-primary" type="button">Купить</button>
    </div>

    8. Комментарии — умеренно

    <!-- Начало секции каталога -->
    <section class="catalog">
      ...
    </section>
    <!-- /Конец секции каталога -->
    
    <!-- Временно скрыто до запуска -->
    <!-- <div class="promo-banner">...</div> -->

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

    9. Не смешивать семантику и представление

    <!-- ПЛОХО: используем теги для стилизации, не для семантики -->
    <b>Важный текст</b>   <!-- b = просто жирный -->
    <i>Иностранное слово</i>  <!-- i = просто курсив -->
    <br /><br />  <!-- Отступы через br — нет! -->
    
    <!-- ХОРОШО: теги по смыслу, отступы через CSS -->
    <strong>Важный текст</strong>  <!-- strong = важность -->
    <em>Иностранное слово</em>    <!-- em = акцент -->

    10. Валидация — проверяй результат

    Инструмент: validator.w3.org — официальный валидатор W3C. Вставь URL или HTML-код и получи список ошибок. В реальных проектах валидацию интегрируют в CI/CD.

    Чеклист перед сдачей HTML

  • [ ] DOCTYPE есть
  • [ ] lang задан у html
  • [ ] charset UTF-8 первым в head
  • [ ] viewport для мобильных
  • [ ] title уникальный, до 60 символов
  • [ ] Все img имеют alt
  • [ ] Все input имеют label
  • [ ] Один h1 на странице
  • [ ] Заголовки в правильной иерархии
  • [ ] Теги строчные
  • [ ] Атрибуты в двойных кавычках
  • [ ] Корректная вложенность
  • В реальных проектах

    В командах используют линтеры для HTML: HTMLHint, html-validate. Prettier форматирует HTML автоматически. Обзор кода (code review) всегда включает проверку HTML-качества. Хороший HTML — это уважение к коллегам, поисковикам и пользователям.

    Примеры

    Генерация и форматирование валидного HTML документа

    // Генерируем корректный HTML-документ программно
    function createHTMLDocument(config) {
      const lines = []
    
      lines.push('<!DOCTYPE html>')
      lines.push('<html lang="' + (config.lang || 'ru') + '">')
      lines.push('  <head>')
      lines.push('    <meta charset="UTF-8" />')
      lines.push('    <meta name="viewport" content="width=device-width, initial-scale=1.0" />')
      lines.push('    <title>' + config.title + '</title>')
      if (config.description) {
        lines.push('    <meta name="description" content="' + config.description + '" />')
      }
      lines.push('  </head>')
      lines.push('  <body>')
      lines.push('    <header>')
      lines.push('      <nav>')
      lines.push('        <ul>')
      config.navLinks.forEach(link => {
        lines.push('          <li><a href="' + link.href + '">' + link.text + '</a></li>')
      })
      lines.push('        </ul>')
      lines.push('      </nav>')
      lines.push('    </header>')
      lines.push('    <main>')
      lines.push('      <h1>' + config.h1 + '</h1>')
      lines.push('    </main>')
      lines.push('    <footer>')
      lines.push('      <p>' + config.footer + '</p>')
      lines.push('    </footer>')
      lines.push('  </body>')
      lines.push('</html>')
    
      return lines
    }
    
    const html = createHTMLDocument({
      lang: 'ru',
      title: 'Sneaker Shop — Кроссовки онлайн',
      description: 'Лучший магазин кроссовок',
      h1: 'Каталог кроссовок',
      navLinks: [
        { href: '/', text: 'Главная' },
        { href: '/catalog', text: 'Каталог' },
        { href: '/about', text: 'О нас' },
      ],
      footer: '© 2024 Sneaker Shop',
    })
    
    html.forEach(line => console.log(line))
    console.log('Строк в документе:', html.length)

    HTML-линтер — проверка типичных ошибок

    // Простой HTML-линтер (проверяем правила через строки)
    function lintHTML(htmlString) {
      const errors = []
      const warnings = []
    
      // Проверка DOCTYPE
      if (!htmlString.includes('<!DOCTYPE html>')) {
        errors.push('Нет <!DOCTYPE html>')
      }
    
      // Проверка lang
      if (!htmlString.includes('lang=')) {
        errors.push('Нет атрибута lang у <html>')
      }
    
      // Проверка charset
      if (!htmlString.includes('charset=')) {
        errors.push('Нет meta charset')
      }
    
      // Проверка title
      if (!htmlString.includes('<title>')) {
        errors.push('Нет тега <title>')
      }
    
      // Проверка заглавных тегов
      if (/<[A-Z]/.test(htmlString)) {
        warnings.push('Найдены теги в верхнем регистре — используй строчные')
      }
    
      // Проверка атрибутов без кавычек
      if (/=w+[s>]/.test(htmlString.replace(/="[^"]*"/g, ''))) {
        warnings.push('Возможны атрибуты без кавычек')
      }
    
      // Проверка img без alt
      const imgWithoutAlt = (htmlString.match(/<img(?![^>]*alt=)[^>]*>/g) || []).length
      if (imgWithoutAlt > 0) {
        errors.push('Найдено ' + imgWithoutAlt + ' тег(ов) img без alt')
      }
    
      return { errors, warnings }
    }
    
    const badHTML = `<HTML>
      <head>
        <title>Мой сайт</title>
      </head>
      <body>
        <IMG src="photo.jpg" />
        <div class=wrapper>Контент</div>
      </body>
    </HTML>`
    
    const result = lintHTML(badHTML)
    console.log('Ошибок:', result.errors.length)
    result.errors.forEach(e => console.log('ОШИБКА: ' + e))
    console.log('Предупреждений:', result.warnings.length)
    result.warnings.forEach(w => console.log('ПРЕДУПРЕЖДЕНИЕ: ' + w))

    Задание

    Напиши валидный HTML-документ по всем правилам хорошего HTML: правильная структура с DOCTYPE, lang, charset, viewport, уникальный title до 60 символов, h1 на странице один, все img с alt, теги строчные, атрибуты в двойных кавычках, классы в kebab-case.

    Подсказка

    lang="ru" для русскоязычного сайта. charset="UTF-8". viewport: width=device-width, initial-scale=1.0. Один h1 на страницу. img всегда с alt — пустой alt="" для декоративных. Теги строчные: <header>, <main>, <footer>. Классы в kebab-case: page-container, site-header, site-footer.

    Загружаем среду выполнения...
    Загружаем AI-помощника...