Жизнь без CSS ... Возможно ли?

CSS мне не друг

Я был очень заинтригован, когда посмотрел Выступление Мэтью Гриффита на Elm Europe 2017. Я всегда избегал глубокого погружения в CSS. Для меня это просто огромная умственная нагрузка. Язык сложный, нет никаких гарантий, что вы пишете правильный код, а путаница между макетом и стилем просто огромна. Практически невозможно изменить макет, не касаясь файлов HTML и CSS. Кроме того, очень вероятно, что небольшое изменение макета в одной части вашего дизайна повлияет на многие другие части вашего дизайна. В общем, я съеживаюсь каждый раз, когда мне нужно изменить стиль веб-сайта.

Что такое Elm Style Elements?

Elm Style Elements - это библиотека, которая обеспечивает альтернативный подход к управлению макетом и стилями в Elm. Основная идея библиотеки заключается в том, что стиль (цвет, размер шрифта и т. Д.) Должен быть отделен от макета (расстояние между блоками, размеры, обтекание и т. Д.). Все атрибуты макета обрабатываются в представлении безопасным для типов способом, а атрибуты стиля обрабатываются вне представления таким же образом, как и мы в настоящее время используем CSS (но безопасным для типов).

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

В этом пакете есть несколько ключевых принципов компоновки, которые делают компоновку более пуленепробиваемой и менее хрупкой.

  1. Основной элемент дизайна, el, может иметь только один дочерний элемент. Если вы хотите представить несколько элементов в контейнере, вы должны явно использовать элемент row или column. Это означает, что вы не можете проектировать с неоднозначными элементами дизайна.
  2. В элементах стиля нет понятия поля. Это в конечном итоге является большим выигрышем, потому что без маржи гораздо сложнее изменить размер одного подэлемента, чтобы вызвать изменения макета, которые отрицательно повлияют на содержащиеся элементы.

Вот простой пример элемента.

row MyRowStyle [ padding 10, spacing 7 ] 
    [ el MyStyle [] empty
    , el MyStyle [] empty
    , el MyStyle [] empty
    ]

Это создает строку из трех элементов с 7 пикселями расстояния между элементами и 10 пикселями заполнения вне блока из трех элементов. Это легко увидеть на этой диаграмме, которую я позаимствовал из Документации по элементам стиля (которая превосходна и ее обязательно нужно прочитать).

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

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

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

type MyStyles
    = Title

stylesheet =
    Style.syleSheet
        [ Style.style Title
            [ Color.text darkGrey
            , Color.background white
            , Font.size 5 -- all units given as px
            ]
        ]

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

Тест-драйв библиотеки

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

Создание макета

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

view model =
    Element.layout AppStyles.stylesheet <|
        pageWrapper
pageWrapper = 
    Element.row AppStyles.PageStyle
        [ padding 20
        , paddingTop 0
        , paddingBottom 0
        ]
        [ pageArea ]
pageArea =
    Element.column AppStyles.PageStyle
        [ width (percent 100) ]
        [ headerArea
        , contentArea
        , footerArea
        ]
headerArea =
    el AppStyles.HeaderStyle
        []
        (Element.text "Header")
footerArea =
    el AppStyles.FooterStyle
        []
        (Element.text "Footer")

Элемент contentArea дополнительно разбит на боковую панель и основное содержимое, как показано ниже.

contentArea =
    Element.row AppStyles.ContentStyle
        []
        [ sidebarArea
        , mainContentArea
        ]
sidebarArea =
    Element.column AppStyles.SidebarStyle
      [ paddingLeft 20
      , paddingTop 50
      , width (percent 20)
      ]
      [ Element.text "Sidebar"
      , Element.text "Sidebar"
      , Element.text "Sidebar"
      , Element.text "Sidebar"
      , Element.text "Sidebar"
      ]
mainContentArea model =
    Element.wrappedRow AppStyles.BodyStyle
        [ padding 10, spacing 7, width (percent 80)]
        (blocks model)
blocks =
    List.map (\elem -> (singleBlock elem))
        [ "1", "2", "3", "4", "5", "6","7", "8"
        , "9", "A", "B", "C", "D", "E", "F" ]
singleBlock value =
    el AppStyles.BlockStyle
        [ width (percent 33), height (px 100) ]
        (Element.text value)

Опять же, мы используем знакомую композицию функций Elm для составления контейнеров, включающих другие контейнеры. Обратите внимание, что здесь собраны все требования к макету. Элементы row и column описывают отношения блоков и отступы, интервал и ширину опишите размер и интервал.

Добавление стилей

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

module AppStyles exposing (..)
import Style exposing (..)
import Style.Font as Font
import Style.Color as Color
import Color exposing (..)
type MyStyles
    = BlockStyle
    | BodyStyle
    | PageStyle
    | ContentStyle
    | HeaderStyle
    | FooterStyle
    | SidebarStyle
sansSerif =
    Font.typeface [ Font.font "Helvetica" ]
stylesheet : StyleSheet MyStyles variation
stylesheet =
    Style.styleSheet
        [ Style.style BodyStyle
            [ Color.background grey
            ]
        , Style.style BlockStyle
            [ sansSerif
            , Color.text black
            , Color.background yellow
            , Font.size 50
            ]
        , Style.style HeaderStyle
            [ sansSerif
            , Font.size 50
            , Color.background darkGrey
            ]
        , Style.style FooterStyle
            [ sansSerif
            , Font.size 50
            , Color.background darkGrey
            ]
        , Style.style SidebarStyle
            [ sansSerif
            , Font.size 20
            , Color.background grey
            ]
        , Style.style PageStyle []
        , Style.style ContentStyle []
        ]

Я импортирую этот модуль в свое представление, и теперь я полностью разделил стили и макет. Кроме того, все эти стили проверяются по типу и не требуют внешнего CSS.

Резюме

Elm Style Elements - довольно новая библиотека, но мой короткий тест-драйв произвел на меня большое впечатление. Он перемещает макет прямо в представление, где, как мне кажется, он принадлежит, и позволяет стилям быть отдельными и полностью проверять тип. Если вы хотите увидеть пример из этого поста в полной мере (включая отзывчивость), вы можете проверить репозиторий git по адресу: https://github.com/billperegoy/elm-page-layout.

Вам может быть интересно, как адаптивные страницы обрабатываются с помощью элементов стиля. Используя подписки Elm, вы можете использовать размер страницы для динамического изменения представления. Я расскажу об этом в следующем посте.