Простой, легкий HTML шаблон без использования gulp сборки

Пример реализации простого, оптимизированного HTML шаблона без gulp и прочих сборок, с поддержкой базового SEO. Подойдет для верстки простеньких страниц.

Оглавление статьи

  1. Вводная часть
  2. Архитектура шаблона
  3. Содержимое файла .editorconfig
  4. Содержимое файла .gitignore
  5. Содержимое файла index.html
  6. Содержимое файла manifest.json
  7. Содержимое файла README.md
  8. Содержимое файла style.css
  9. Содержимое файла script.js

Вводная часть

Основная идея заключается в создании заготовки простенького шаблона, который можно было бы повторно использовать для верстки каких то не больших страничек. Так же хотелось, чтобы шаблон имел базовое SEO и заготовки в виде скриптов Google Analytics и Yandex Metrika.

Архитектура шаблона

Будем использовать стандартный подход в именовании и расположении файлов html проекта. Создайте в корне проекта следующие файлы и каталоги.

BASH
./
├── css
├── fonts
├── img
├── js
├── .editorconfig
├── .gitignore
├── index.html
├── manifest.json
└── README.md
  • css - содержит стили
  • fonts - содержит шрифты
  • img - содержит изображения
  • js - содержит JavaScript скрипты
  • .editorconfig - содержит правила написания кода
  • .gitignore - содержит перечень файлов и каталогов, которые не будут добавлены в репозиторий git
  • index.html - содержит разметку главной страницы
  • manifest.json - содержит информацию об иконках, цветовой теме, ориентации экрана, начальном URL и т.д.
  • README.md - содержит описание проекта и инструкцию по его развертыванию

Содержимое файла .editorconfig

Более подробно ознакомиться с настройками конфигурационного файла .editorconfig можно на официальном сайте.

.EDITORCONFIG
# Корневой файл .editorconfig
root = true

# Все файлы
[*]
charset = utf-8 # кодировка
indent_style = space # отступ через пробел
indent_size = 2 # размер отступа 2 символа
end_of_line = lf # unix стиль новой строки
trim_trailing_whitespace = true # удалять пробелы в конце строк
insert_final_newline = true # оставлять в конце файла пустую строку

# Md файлы
[*.md]
trim_trailing_whitespace = false # удалять пробелы в конце строк

Содержимое файла .gitignore

Содержит перечень файлов и каталогов, которые не будут добавлены в репозиторий git. Исключим стандартные каталоги создаваемые программами VSCode и PhpStorm.

.idea
.vscode

Содержимое файла index.html

Создадим файл index.html и с помощью Emmet разворачиваем базовую разметку, введя ! знак, и нажав Tab. Должно получиться примерно следующее.

HTML
<!doctype html>
<html lang="ru">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Document</title>
</head>
<body>

</body>
</html>

Базовые дополнения

Внесем базовые нюансы для нашего шаблона.

HTML
<!-- class="no-js" - по умолчанию предполагаем, что у пользователя отключен в браузере JS. -->
<!-- Это позволит стилизовать некоторые задействованные в js элементы как то иначе, когда JS отключен. -->
<html class="no-js" lang="ru">

<!-- Мета информация с кратким описанием страницы -->
<meta name="description" content="Описание главной страницы">

<!-- Скрипт удаляющий из html тега класс no-js. -->
<!-- Если у пользователя включен JS, то смысла в альтернативной стилизации элементов нет. -->
<script>document.documentElement.classList.remove('no-js')</script>

Добавим стили

Подключим в шаблон CSS стили. Параллельно с этим пунктом создадим в каталоге css файл style.css, а так же скачаем в него библиотеку normalize.css.

В каталоге css должна получиться следующая структура.

HTML
./css/
├── normalize.css
└── style.css

Подключим файлы стилей в файл index.html.

HTML
<!-- Добавим заготовку под критические стили. -->
<!-- Сюда будет выноситься часть скриптов, участвующих в стилизации первого экрана. -->
<style></style>

<!-- Подключим CSS файлы. -->
<!-- К названию файлы добавим так же номер версии ?v=0.0.1, для борьбы с кешированием. -->
<!-- Атрибут onload="this.rel='stylesheet'" дает возможность браузеру отложить загрузку файла
со стилями и приступить непосредственно к чтению тегов страницы. Только после полной отрисовки DOM дерева
будет загружен файл со стилями. Что положительно влияет на показатели Page Speed. -->
<link rel="preload" as="style" href="/css/normalize.css?v=0.0.1" onload="this.rel='stylesheet'">
<link rel="preload" as="style" href="/css/style.css?v=0.0.1" onload="this.rel='stylesheet'">

<!-- Так как атрибут onload сработает только при включенном JS мы подстрахуемся и добавим возможность
загружать CSS стили стандартным способом при выключенном JS. -->
<noscript>
  <link rel="stylesheet" href="/css/normalize.css?v=0.0.1">
  <link rel="stylesheet" href="/css/style.css?v=0.0.1">
</noscript>

Добавим предзагрузку шрифтов

Когда мы используем в проекте не стандартные шрифты, рекомендуется заранее подсказать браузеру об их загрузки. Для того чтобы браузер заранее начал скачивать пользовательские шрифты.

Добавим в каталог fonst какой-нибудь кастомный шрифты формата woff2, например Roboto и подключим его в файле index.html

HTML
<link rel="preload" as="font" href="/fonts/roboto/roboto-regular.woff2" type="font/woff2" crossorigin="anonymous">

Добавим SEO мета данные

Добавим поддержку Open Graph, Twitter Card и микроразметку JSON-LD.

HTML
<!-- Основная ссылка на текущую страницу. -->
<link rel="canonical" href="http://localhost:3000">

<!-- Мета данные для Apple устройств -->
<meta name="application-name" content="Главная страница — Название сайта">
<meta name="apple-mobile-web-app-title" content="Главная страница — Название сайта">

<!-- Мета данные Open Graph -->
<meta property="og:title" content="Главная страница — Название сайта">
<meta property="og:locale" content="ru">
<meta property="og:description" content="Описание главной страницы">
<meta property="og:url" content="http://localhost:3000">
<meta property="og:site_name" content="Описание главной страницы">
<meta property="og:type" content="website">
<meta property="og:image" content="http://localhost:3000/img/cover.jpg">

<!-- Мета данные Twitter Card -->
<meta property="twitter:card" content="summary">
<meta property="twitter:title" content="Главная страница — Название сайта">
<meta property="twitter:image" content="http://localhost:3000/img/cover.jpg">

<!-- Микроразметку JSON-LD для простой страницы -->
<script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "WebSite",
    "headline": "Главная страница — Название сайта",
    "description": "Описание главной страницы",
    "name": "Описание главной страницы",
    "url": "http://localhost:3000"
  }
</script>

<!-- Микроразметку JSON-LD для страницы со статей -->
<!-- Необходимо использовать один из вариантов в зависимости от назначения страницы. -->
<!--
<script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    "dateModified": "2023-12-31T00:00:00+06:00",
    "datePublished": "2023-12-31T00:00:00+06:00",
    "headline": "Страница — Название сайта",
    "description": "Описание страницы",
    "name": "Описание страницы",
    "url": "http://localhost:3000"
  }
</script>
-->

Добавим стилизацию страницы для мобильных устройств

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

HTML
<meta name="theme-color" content="#000000">
<meta name="msapplication-navbutton-color" content="#000000">
<meta name="apple-mobile-web-app-status-bar-style" content="#000000">

Добавим фавиконки

Небольшая иконка отображающаяся на вкладке браузера. Рекомендуется подключать сразу несколько иконок различного размера, для корректного отображения ее на различных устройствах.

Загрузим в каталог ./img/favicons следующие иконки:

  • favicon.ico - размер иконки должен быть 32х32
  • icon.svg - масштабируемая иконка под любые размеры
  • apple-touch-icon.png - размер иконки должен быть 180х180
  • icon-192.png - размер иконки должен быть 192х192, будет использоваться в файле manifest.json
  • icon-512.png - размер иконки должен быть 512х512, будет использоваться в файле manifest.json

Подключим фавиконки в файл index.html.

HTML
<link rel="icon" href="/img/favicons/favicon.ico" sizes="any">
<link rel="icon" href="/img/favicons/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/img/favicons/apple-touch-icon.png">
<link rel="manifest" href="/manifest.json">

Добавим Google Analytics и Yandex Metrika

Подключим скрипты для индексации страницы в поисковых системах.

HTML
<!-- Google Analytics -->
<!-- <script async>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-XXXXXX');</script> -->

<!-- Yandex Metrika -->
<!-- <script async>(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)}) (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym"); ym(XXXXXX, "init", {});</script> -->

После открывающего тега body подключим эти же скрипты, но только для браузера в котором отключен JS.

HTML
<!-- Google Analytics -->
<!--<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXX" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>-->

<!-- Yandex Metrika -->
<!--<noscript><img src="https://mc.yandex.ru/watch/XXXXXX" style="position:absolute; left:-9999px;" alt=""></noscript>-->

В дальнейшем получив уникальный идентификатор необходимо будет заменить в скриптах GTM-XXXXXX и XXXXXX на свои.

Добавим уведомление об отключеном JS

Создадим специфичную разметку с уведомлением для пользователей с отключенным JS.

HTML
<!-- JavaScript отключен -->
<noscript><p class="notice"><strong>JavaScript отключен</strong>, некоторые функции сайта не доступны. Пожалуйста <a rel="nofollow" href="https://support.google.com/adsense/answer/12654" target="_blank">включите JavaScript</a>!</p></noscript>

Добавим svg спрайт

Создадим вручную svg спрайт, для этого скачайте любую svg иконку и скопируйте ее path тег целиком, для того, чтобы позже добавить ее на страницу.

HTML
<!-- Svg sprite -->
<!-- Блок содержащий спрайт скрываем, чтобы всего его содержимое не отображалось на странице. -->
<div hidden>
  <svg xmlns="http://www.w3.org/2000/svg">
    <!-- Добавляем содержимое скаченной svg иконки в тег symbol. -->
    <!-- Каждой иконки в наборе svg спрайта необходимо задавать уникальный id. -->
    <!-- В данном случае у нас одна иконка с id="icon-user". -->
    <symbol id="icon-user" viewBox="0 0 24 24" fill="none">
      <path d="M17.2166 19.3323C15.9349 17.9008 14.0727 17 12 17C9.92734 17 8.06492 17.9008 6.7832 19.3323M12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21ZM12 14C10.3431 14 9 12.6569 9 11C9 9.34315 10.3431 8 12 8C13.6569 8 15 9.34315 15 11C15 12.6569 13.6569 14 12 14Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
    </symbol>
  </svg>
</div>

Добавим базовую разметку

Создадим некоторую разметку на которой протестируем функционал шаблона.

HTML
<div class="container">
  <!-- Таким образом выводится нужная картинка из svg спрайта. -->
  <!-- Вывод производится по ее id имени. -->
  <svg width="50" height="50" aria-hidden="true"><use href="#icon-user"></use></svg>

  <h2>Простой HTML шаблон</h2>
  <p>Пример реализации простого <b>HTML</b> шаблона, без <b>Gulp</b> сборки. С базовой <b>SEO</b> настройкой.</p>
  <p>Подойдет для верстки простых одностраничных сайтов (landing page).</p>

  <!-- В каталог img добавил некоторую картинку и отобразил ее на странице. -->
  <p style="margin-top: 40px"><img src="/img/pagespeed.jpg" width="653" height="739" alt="Page Speed статистика" loading="lazy" fetchpriority="high"></p>
</div>

Добавим скрипт

Подключим в шаблон JS скрипт. Создадим в каталоге js файл script.js и подключим его в шаблон.

HTML
<script type="module" src="/js/script.js?v=0.0.1"></script>

Конечный вариант

Мы полностью закончили с заполнением содержимого файла index.html и вот, что у нас получилось.

HTML
<!DOCTYPE html>
<html class="no-js" lang="ru">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <title>Главная страница — Название сайта</title>
  <meta name="description" content="Описание главной страницы">

  <script>document.documentElement.classList.remove('no-js')</script>

  <!-- Критические стили -->
  <style></style>

  <link rel="preload" as="style" href="/css/normalize.css?v=0.0.1" onload="this.rel='stylesheet'">
  <link rel="preload" as="style" href="/css/style.css?v=0.0.1" onload="this.rel='stylesheet'">
  <noscript>
    <link rel="stylesheet" href="/css/normalize.css?v=0.0.1">
    <link rel="stylesheet" href="/css/style.css?v=0.0.1">
  </noscript>

  <link rel="preload" as="font" href="/fonts/roboto/roboto-regular.woff2" type="font/woff2" crossorigin="anonymous">

  <link rel="canonical" href="http://localhost:3000">
  <meta name="application-name" content="Главная страница — Название сайта">
  <meta name="apple-mobile-web-app-title" content="Главная страница — Название сайта">
  <meta property="og:title" content="Главная страница — Название сайта">
  <meta property="og:locale" content="ru">
  <meta property="og:description" content="Описание главной страницы">
  <meta property="og:url" content="http://localhost:3000">
  <meta property="og:site_name" content="Описание главной страницы">
  <meta property="og:type" content="website">
  <meta property="og:image" content="http://localhost:3000/img/cover.jpg">
  <meta property="twitter:card" content="summary">
  <meta property="twitter:title" content="Главная страница — Название сайта">
  <meta property="twitter:image" content="http://localhost:3000/img/cover.jpg">
  <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@type": "WebSite",
      "headline": "Главная страница — Название сайта",
      "description": "Описание главной страницы",
      "name": "Описание главной страницы",
      "url": "http://localhost:3000"
    }
  </script>
  <!--
  <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@type": "BlogPosting",
      "dateModified": "2023-12-31T00:00:00+06:00",
      "datePublished": "2023-12-31T00:00:00+06:00",
      "headline": "Страница — Название сайта",
      "description": "Описание страницы",
      "name": "Описание страницы",
      "url": "http://localhost:3000"
    }
  </script>
  -->

  <meta name="theme-color" content="#000000">
  <meta name="msapplication-navbutton-color" content="#000000">
  <meta name="apple-mobile-web-app-status-bar-style" content="#000000">

  <link rel="icon" href="/img/favicons/favicon.ico" sizes="any">
  <link rel="icon" href="/img/favicons/icon.svg" type="image/svg+xml">
  <link rel="apple-touch-icon" href="/img/favicons/apple-touch-icon.png">
  <link rel="manifest" href="/manifest.json">

  <!-- Google Analytics -->
  <!-- <script async>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-XXXXXX');</script> -->

  <!-- Yandex Metrica -->
  <!-- <script async>(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)}) (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym"); ym(XXXXXX, "init", {});</script> -->

</head>
<body>
<!-- Google Analytics -->
<!--<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXX" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>-->

<!-- Yandex Metrica -->
<!--<noscript><img src="https://mc.yandex.ru/watch/XXXXXX" style="position:absolute; left:-9999px;" alt=""></noscript>-->

<!-- JavaScript отключен -->
<noscript><p class="notice"><strong>JavaScript отключен</strong>, некоторые функции сайта не доступны. Пожалуйста <a rel="nofollow" href="https://support.google.com/adsense/answer/12654" target="_blank">включите JavaScript</a>!</p></noscript>

<!-- Svg sprite -->
<div hidden>
  <svg xmlns="http://www.w3.org/2000/svg">
    <symbol id="icon-user" viewBox="0 0 24 24" fill="none">
      <path d="M17.2166 19.3323C15.9349 17.9008 14.0727 17 12 17C9.92734 17 8.06492 17.9008 6.7832 19.3323M12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21ZM12 14C10.3431 14 9 12.6569 9 11C9 9.34315 10.3431 8 12 8C13.6569 8 15 9.34315 15 11C15 12.6569 13.6569 14 12 14Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
    </symbol>
  </svg>
</div>

<div class="container">
  <svg width="50" height="50" aria-hidden="true"><use href="#icon-user"></use></svg>

  <h2>Простой HTML шаблон</h2>
  <p>Пример реализации простого <b>HTML</b> шаблона, без <b>Gulp</b> сборки. С базовой <b>SEO</b> настройкой.</p>
  <p>Подойдет для верстки простых одностраничных сайтов (landing page).</p>

  <p style="margin-top: 40px"><img src="/img/pagespeed.jpg" width="653" height="739" alt="Page Speed статистика" loading="lazy" fetchpriority="high"></p>
</div>

<script type="module" src="/js/script.js?v=0.0.1"></script>

</body>
</html>

Содержимое файла manifest.json

manifest.json метаинформация о приложении или расширении, которая позволяет платформе или браузеру правильно обрабатывать и представлять ваше приложение. Ознакомиться со значением свойств можно на сайте mdn.

JSON
{
  "name": "Название сайта",
  "short_name": "Название сайта",
  "description": "Описание сайта",
  "lang": "ru",
  "dir": "ltr",
  "id": "/",
  "start_url": "/",
  "scope": "/",
  "display": "minimal-ui",
  "orientation": "any",
  "theme_color": "#000000",
  "background_color": "#000000",
  "prefer_related_applications": false,
  "icons": [
    {
      "src": "/img/favicons/icon-192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "/img/favicons/icon-512.png",
      "type": "image/png",
      "sizes": "512x512"
    },
    {
      "src": "/img/favicons/icon.svg",
      "sizes": "any",
      "type": "image/svg",
      "purpose": "maskable"
    }
  ]
}

В целом значение многих свойств понятны из контекста выделю лишь некоторые:

  • dir - направление текста приложения, может быть слева-направо, справа-налево
  • id - позволяет явно определить идентификатор, используемый для вашего приложения
  • start_url - сообщает браузеру по какой ссылку открывать приложение
  • scope - набор URL-адресов, которые браузер считает принадлежащими вашему приложению, и используется для принятия решения о том, когда пользователь покинул приложение
  • display - настраивает вид пользовательского интерфейса браузера, может иметь значение fullscreen, standalone, minimal-ui, browser
  • prefer_related_applications - это логическое значение, которое используется в качестве подсказки пользовательскому агенту, чтобы сказать, что связанные приложения должны быть предпочтительнее веб-приложения.

Содержимое файла README.md

Пользовательское описание проекта в формате Markdown, так же может включать в себя инструкцию по развертыванию.

MD
# Простой HTML шаблон

Пример реализации простого **HTML** шаблона, без **Gulp** сборки. С базовой **SEO** настройкой.

Подойдет для верстки простых одностраничных сайтов (landing page).

![Page Speed статистика](https://raw.githubusercontent.com/eliofery/simple-html-template/main/img/pagespeed.jpg)

## Режим разработки
```bash
npx browser-sync start --server --no-notify --no-ui --files '*.html,css/**/*.css,img/*'
```

Содержимое файла style.css

Базовое содержимое стилей. Хорошо бы вынести содержимое переменных и базовых стилей в отдельные файлы, но пока ограничимся одним файлом.

CSS
/* Переменные */
:root {
--fz-label: 117px;
--fz-heading: 78px;
--fz-heading-2: 55px;
--fz-heading-3: 24px;
--fz-heading-4: 18px;
--fz-heading-5: 16px;

--color-black: #000;
--color-white: #fff;

--width-container: 360px;
--gutter: 20px;
}

@media screen and (min-width: 768px) {
  :root {
    --width-container: 768px;
    --gutter: 40px;
  }
}

@media screen and (min-width: 1440px) {
  :root {
    --width-container: 1440px;
  }
}

/* Базовая разметка */
@font-face {
  font-family: Roboto;
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/roboto/roboto-regular.woff2") format("woff2");
}

*,
*::before,
*::after {
  box-sizing: inherit;
}

html {
  box-sizing: border-box;
  height: 100%;
}

body {
  position: relative;

  min-width: var(--width-container);
  min-height: 100%;

  color: var(--color-black);
  font-family: "Roboto", Arial, sans-serif;
  font-size: var(--fz-heading-5);
  line-height: 1.5;

  background-color: var(--color-white);
}

img {
  max-width: 100%;
  height: auto;
}

.sr-only {
  position: absolute;

  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;

  border: 0;

  clip: rect(0,0,0,0);
  -webkit-clip-path: inset(100%);
  clip-path: inset(100%);
}

.container {
  max-width: var(--width-container);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.notice {
  margin: 0;
  padding: 10px;

  color: white;
  text-align: center;

  background-color: black;
}

.notice a {
  color: yellow;
}

.notice a:hover,
.notice a:focus {
  text-decoration: none;
}

Содержимое файла script.js

Изначальное содержимое будет пустым, так как на страницу шаблона мы не добавляли динамических элементов.

Простой HTML шаблон готов к использованию. С полным кодом статьи можно ознакомиться в моем репозитории.

Предыдущая статья Установка и настройка Xdebug для отладки PHP кода Следующая статья Gulp сборка для верстки с использованием Pug шаблонизатора