Верстаем статический web-сайт с помощью Python3x, базовый шаблон

Jazz

Опубликован:  2024-02-10T02:50:31.905062Z
Отредактирован:  2024-02-10T02:50:31.905062Z
Статус:  публичный
25
0
0

Продолжаем разработку sitefish - web-приложения для статического web-сайта. На текущий момент в проекте всё готово, чтобы наконец-то приступить к вёрстке страниц сайта. И в этом выпуске я покажу обычный способ, как можно избежать повторения html-кода при вёрстке страниц. На этом этапе разработки web-приложения будем верстать так называемый базовый шаблон. Поскольку проект построен на основе языка программирования Python3x, html-код страниц генерируется программой автоматически, в соответствии с логикой заданного для конкретного URL-адреса обработчика и по индивидуальному html-шаблону. В этом проекте шаблоны будут построены на основе Jinja2 - эта библиотека уже подключена в проект. Приступим...

Шаблоны Jinja2

Библиотеку Jinja2 я подключал в проект на начальном этапе конфигурации в файле __inint__.py базового каталога sitefish. Эта библиотека предоставляет разработчику специальный синтаксис и целый набор полезных возможностей и разнообразных логических блоков, по ссылке в начале этого абзаца можно найти описание всего этого великолепия.

В этом цикле статей я рассказываю о разработке статического web-сайта, шаблоны sitefish буду содержать минимум специфических элементов Jinja2, в этой демонстрации я покажу только наследование и переопределение блоков - обычные инструменты, исключающие повторение html-кода.

Кроме этого, в проект подключена библиотека webassets, которая позволяет автоматизированно минимизировать код таблиц стилей и сценариев JavaScript в процессе обработки шаблона. Она добавляет в синтаксис Jinja2 собственный оригинальный блок, об этом чуть позже...

Построение базового шаблона

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

$ cd ~/workspace/sitefish/

Активирую виртуальное окружение.

$ source venv/bin/activate

Все далее продемонстрированные команды я буду выполнять в этом терминале, находясь в корневом каталоге проекта.

Приступим к вёрстке базового шаблона. Обычно базовый шаблон верстается на основе макета сайта и состоит из базовых элементов, повторяющихся на всех типовых страницах. Как такового макета для sitefish у меня нет, ибо я не дизайнер, тем не менее определённый образ воображение рисует, этого образа я и буду придерживаться.

Создаю и открываю в текстовом редакторе файл базового шаблона, даю этому файлу соответствующее имя - base.html, и размещаю его в каталоге templates.

$ vim sitefish/templates/base.html

Пишу в этот файл следующий код.

<!DOCTYPE html>
<html lang="ru">
  <head>

    {% block metas %}
    <meta charset="utf-8">
    <meta http-equiv="X-UA-COMPATIBLE" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    {% endblock metas %}

    <title>Sitefish: {% block title %}{% endblock title %}</title>

    {% block styles %}
      <link rel="icon" href="{{ url_for('favicon') }}"
            type="image/vnd.microsoft.icon">
      {% assets filters='cssmin', output='generic/css/vendor.css',
                'vendor/bootstrap/css/bootstrap.css',
                'vendor/bootstrap/css/bootstrap-theme.css' %}
        <link rel="stylesheet" href="{{ ASSET_URL }}">
      {% endassets %}
    {% endblock styles %}

  </head>
  <body></body>
</html>

Как видно, это обычный html-код. Внутри тега <head> с помощью синтаксиса Jinja2 я выделил три блока:

  • блок metas содержит теги <meta>;

  • блок title модифицирует тег <title>;

  • блок styles содержит теги <link>.

Внутри блока styles выделен блок assets, он имеет особый синтаксис и обрабатывается библиотекой webassets, в этом блоке я задал фильтр обработки - cssmin, с помощью которого группируются таблицы стилей, адрес и имя файла в который записываются сгруппированные таблицы стилей, и список файлов, которые обрабатываются и группируются. Здесь я обрабатываю два файла из каталога vendor - этот каталог уже существует и содержит сторонние библиотеки, результат обработки записываю в файл с именем vendor.css.

Фильтр cssmin это специальная программа для минимизации CSS-кода, её нужно установить в виртуальное окружение. В процессе работы над шаблонами sitefish я буду использовать ещё один фильтр - rjsmin, устанавливаю эти пакеты.

$ pip install cssmin rjsmin

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

В используемом макете сайта предусмотрены два общих для всех страниц элемента:

  • главное меню сайта - основной инструмент навигации по страницам;

  • нижняя панель страницы, обычно в сленге web-разработчиков её называют "подвал".

Главное меню сайта я воспроизведу при помощи соответствующих инструментов Bootstrap. На текущем этапе разработки меню будет иметь два пункта: ссылка на стартовую страницу сайта, совмещённая с логотипом, раздел с именем "Компания" с выпадающим меню. Вот как выглядит код этого элемента.

    <nav id="navigation" class="navbar navbar-default">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle"
                  data-toggle="collapse" data-target=".navbar-collapse">
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand"
             href="{{ url_for('index') }}">
            <img alt="logo"
                 src="{{ url_for('static', path='images/logo.png') }}"
                 width="28"
                 height="28">
          </a>
        </div>
        <div class="collapse navbar-collapse">
          <ul class="nav navbar-nav">
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                Компания <b class="caret"></b>
              </a>
              <ul class="dropdown-menu">
                <li>
                  <a href="{{ url_for('page', page='about.html') }}">
                    О компании
                  </a>
                </li>
                <li>
                  <a href="{{ url_for('page', page='contacts.html') }}">
                    Контакты
                  </a>
                </li>
              </ul>
            </li>
          </ul>
        </div>
      </div>
    </nav>

Этот элемент размещаю внутри тега <body>. Здесь следует обратить внимание на атрибут href в тегах <a>. URL-адреса я задаю с помощью вспомогательной функции url_for, её я определил на стадии конфигурации проекта в файле __init__.py. Точно так же задан атрибут src в теге <img>. Используемые с этой функцией параметры тоже определены в файле конфигурации.

В разметке главного меню нужно обратить внимание на классы dropdown и dropdown-menu, это библиотечные классы Bootstrap. С помощью этих классов впоследствии не составит труда добавить в меню дополнительные пункты и ссылки в них с URL-адресами новых страниц сайта.

Второй общий для всех страниц сайта элемент я сверстаю самостоятельно в теге <footer>. Вот его код.

    <footer id="footer">
      <div class="container-fluid">
        <div class="footer-block"></div>
        <div class="footer-content">
          <div class="footer-left text-left">
            <img alt="right finger"
                 src="{{ url_for('static', path='images/footer-left.png') }}"
                 width="24"
                 height="24">
          </div>
          <div class="footer-center text-center">
            <a id="footer-link"
               href="{{ url_for('index') }}">
              <span class="footer-link-text">Sitefish</span>
            </a>
          </div>
          <div class="footer-right text-right">
            <img alt="left finger"
                 src="{{ url_for('static', path='images/footer-right.png') }}"
                 width="24"
                 height="24">
          </div>
          <div class="footer-bottom"></div>
        </div>
        <div class="footer-bottom"></div>
      </div>
    </footer>

Этот элемент размещаю в теге <body> под главным меню.

В базовый шаблон необходимо подключить используемые в проекте библиотеки JavaScript, их я выделю в отдельный блок соответствующим синтаксисом Jinja2 и webassets. Таким образом в шаблоне появляется ещё один блок - scripts, и размещаю я его внутри тега <body> под тегом <footer>, вот как выглядит код этого блока.

    {% block scripts %}
      {% assets filters='rjsmin', output='generic/js/vendor-pub.js',
                'vendor/jquery.js',
                'vendor/bootstrap/js/bootstrap.js',
                'vendor/luxon.js' %}
        <script src="{{ ASSET_URL }}"></script>
      {% endassets %}
    {% endblock scripts %}

Внутри тегов <nav> и <footer> я использовал изображения, поскольку для sitefish я использую макет сайта CodeJ, эти изображения я скопирую прямо с сайта в каталог images. Вот как выглядит дерево корневого каталога sitefish после этой операции.

vVWZkz2Cpg.png

Базовый шаблон для сайта является общим, и его я буду использовать для вёрстки html-файлов всех страниц сайта.

Верстаем страницы сайта

На текущий момент у сайта уже есть три страницы, их html-файлы хранятся в базовом каталоге templates. Начнём с главной страницы - Index Page.

Открываю в текстовом редакторе файл index.html.

$ vim sitefish/templates/main/index.html

Удаляю весь существующий на данный момент код и заменяю его следующим.

{% extends "base.html" %}

{% block title %}Index{% endblock title %}

Здесь я опять использовал синтаксис Jinja2, указал шаблонизатору имя базового шаблона с помощью выражения extends и определил содержание тега <title> в одноимённом блоке. Настало время протестировать этот код. Запускаю в терминале отладочный сервер.

$ python runserver.py

Запускаю браузер, в моём случае это Chromium, и стучусь в нём по адресу стартовой страницы - localhost:5000.

JShOiTqaPH.png

В этом экземпляре браузера я буду отлаживать код страниц сайта, мне нужно, чтобы браузер не записывал используемые на страницах файлы в свой кеш. Отключить запись кеша можно в инструментах разработчика, в Chromium доступ к ним можно получить с помощью сочетания crtl+shift+i. В окне инструментов разработчика перехожу на вкладку "Сеть" и ставлю флаг в поле "Отключить кеш".

Как видно на снимке экрана выше, на странице появились определённые в базовом шаблоне элементы, но выглядят они не совсем так, как мне хотелось бы, это легко исправить, для этого в шаблоне index.html переопределяю блок styles, дописываю в конец файла следующий код.

{% block styles %}
  {{ super() }}
  {% assets filters='cssmin', output='generic/css/main/index.css',
            'css/base.css' %}
    <link rel="stylesheet" type="text/css" href="{{ ASSET_URL }}">
  {% endassets %}
  <link rel="canonical" href="{{ url_for('index') }}">
{% endblock styles %}

Внутри этого блока я использовал функцию super, функция включает все определённые в соответствующем блоке базового шаблона теги, и дополнительный блок assets, в котором сгруппировал файл таблиц стилей index.css. Список файлов, из которых группируется index.css, пока включает в себя один единственный файл - base.css. Он определяет оформление общих для всех страниц сайта элементов макета. Чуть позже, при окончательной вёрстке, я добавлю в этот список другие CSS-файлы по мере необходимости. Создаю этот файл и открываю его в текстовом редакторе.

$ vim sitefish/static/css/base.css

В него пишу следующий код.

html {
  position: relative;
  min-height: 100%;
}

body {
  margin-bottom: 90px;
  font-size: 12pt;
}

#navigation {
  margin: 0;
  border: 1px solid #d3d3d3;
  background-image: linear-gradient(to bottom, #fffef2, #f3f2e7);
  box-shadow: 0 0 8px #d3d3d3;
  color: #666666;
}

.navbar-brand {
  padding-top: 10px;
}

#footer {
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 90px;
  box-shadow: 0 0 1px #333333;
  background-color: #666666;
  background-image: linear-gradient(to bottom, #666666, #333333);
}

.footer-block {
  height: 30px;
}

.footer-left {
  width: 5%;
  float: left;
  margin-top: 5px;
}

.footer-center {
  width: 90%;
  float: left;
  padding-top: 4px;
  color: white;
}

#footer-link {
  color: white;
  text-decoration: none;
  text-shadow: 0 0 8px #d9dcec;
}

#footer-link:hover {
  cursor: pointer;
  text-shadow: 0 0 0 #d9dcec;
}

.footer-link-text {
  font-style: italic;
}

.footer-right {
  width: 5%;
  float: left;
  margin-top: 5px;
}

.footer-bottom {
  clear: both;
}

Сохраняю все правки кода в файлы, перехожу в окно браузера и обновляю страницу.

vxbhMyM38h.png

На странице вижу главное меню и "подвал". В них две ссылки на главную страницу. В меню, кроме этого, есть ещё и раздел "Компания". Пробую нажать на него левой кнопкой мыши.

iwWlbtLS7a.png

В этом разделе размещены ссылки на две другие страницы сайта. Чтобы и они выглядели подобным образом, нужно отредактировать их html-файлы.

Открываю в текстовом редакторе файл about.html.

$ vim sitefish/templates/main/about.html

Удаляю весь код, написанный на предыдущем этапе разработки и заменяю его следующим.

{% extends "base.html" %}

{% block title %}О компании{% endblock title %}

{% block styles %}
  {{ super() }}
  {% assets filters='cssmin', output='generic/css/main/about.css',
            'css/base.css' %}
    <link rel="stylesheet" type="text/css" href="{{ ASSET_URL }}">
  {% endassets %}
{% endblock styles %}

Эта страница тоже является наследницей базового шаблона, в ней переопределён блок title и блок styles. Для группировки файла about.css пока используется единственный файл base.css, но я получаю возможность впоследствии добавлять в этот список другие файлы, для каждого нового элемента можно выделить собственный файл, и из этих файлов группировать стили каждой страницы, на которой эти элементы использованы. Таким образом можно избежать повторения кода.

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

lSGaf6nHy8.png

Как видно на снимке экрана, в окне браузера изменился адрес в адресной строке и текст в заголовке, но страница выглядит точно также, как и предыдущая.

У сайта в текущей редакции есть ещё одна страница, её html-файл тоже нужно переписать. Открываю его в текстовом редакторе.

$ vim sitefish/templates/main/contacts.html

Опять удаляю весь код и заменяю его следующим.

{% extends "base.html" %}

{% block title %}Контакты{% endblock title %}

{% block styles %}
  {{ super() }}
  {% assets filters='cssmin', output='generic/css/main/contacts.css',
            'css/base.css' %}
    <link rel="stylesheet" type="text/css" href="{{ ASSET_URL }}">
  {% endassets %}
{% endblock styles %}

Этот шаблон опять наследует базовый шаблон, в нём переопределены блоки title и styles. Сохраняю изменения в файл, перехожу в окно браузера и с помощью ссылки в главном меню сайта перехожу на страницу "Контакты".

hvkfgN7pqw.png

Все три снимка экрана демонстрируют, что страницы сайта в текущей редакции повторяю оформление макета и выглядят аналогичным образом. Базовый шаблон свёрстан, и я получаю возможность сосредоточиться на вёрстке каждой отдельной страницы, изменяя и дополняя её шаблон.

Управление webassets

Как известно, современные браузеры умеют показывать не только страницы сайтов, но и исходный код этих страниц. При разработке и тестировании сайта очень часто возникает потребность заглянуть в исходный код, дабы убедиться, что интерпретация шаблона происходит в полном соответствии с замыслом разработчика. Прямо сейчас меня интересует состояния тегов <link> и <script>. Находясь в окне браузера жму правую кнопку мыши и в контекстном меню выбираю пункт "Просмотр кода страницы", как альтернатива - можно воспользоваться клавиатурным сочетанием ctrl+u. В результате оказываюсь на вкладке с исходным кодом страницы. Меня интересуют теги <link>.

eWFuJSeFEu.png

Обращаю внимание, что в этих тегах числятся файлы bootstrap.css, bootstrap-theme.css и base.css. Первые два тега определены в базовом шаблоне, а последний в шаблоне данной конкретной страницы. Если перейти по ссылкам в этих тегах, можно убедиться, что код файлов CSS транслируется на страницу в неизменном виде. Но мне нужно этот код минимизировать. Как?

На стадии конфигурации проекта я подключил в файле конфигурации библиотеку webassets - именно эта библиотека управляет обработкой статических файлов, и в файле настроек на текущий момент присутствует опция ASSETS_DEBUG. Что ж, давайте поменяем значение этой опции. Открываю файл настроек приложения.

$ vim .env

И модифицирую его код следующим образом.

DEBUG=True
ASSETS_DEBUG=False

Сохраняю изменения в файл. Останавливаю отладочный сервер, для этого окно терминала в котором сервер запущен делаю активным и жму ctrl+c. Вновь запускаю сервер.

$ python runserver.py

Каждая правка файла настроек должна сопровождаться перезапуском отладочного сервера, чтобы внесённые изменения вступили в силу. Перехожу в окно браузера, обновляю вкладку с исходным кодом открытой страницы и обращаю внимание на теги <link>.

07hVW2k2iD.png

И теперь я вижу, что в исходном коде вместо трёх тегов <link> присутствует два, а ссылки в них невероятным образом изменились. Если проследовать по этим ссылкам, можно увидеть минимизированный исходных код результирующих файлов, которые сгруппированы из перечисленных в соответствующем блоке assets соответствующего шаблона.

Делаю простой вывод: изменяя опцию ASSETS_DEBUG разработчик получает возможность видеть исходный код на стадии разработки проекта, или минимизированный код в продакшене.

Git

На текущий момент все цели этой демонстрации полностью достигнуты, базовый шаблон свёрстан, и все необходимые блоки в нём выделены. Пришло время сделать очередной commit. Давайте взглянем на статус репозитория.

$ git status

0n09mDqkTf.png

Как видно на снимке экрана, наряду с другими изменениями, в проекте появились два каталога (.webassets-cache и generic), созданные в результате обработки кода инструментами библиотеки webassets, и этим каталогам не место на публичном Git-сервере, их обработку нужно исключить. Для этого открываю в текстовом редакторе файл .gitignore.

$ vim .gitignore

И дописываю в конец файл две дополнительные строчки с относительными адресами каталогов .webassets-cache и generic.

jhQHy4y5JP.png

Сохраняю изменения в файл и делаю очередной commit. Текущий этап разработки завершен, продолжение следует.

Продолжение следует

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