Svelte Shy Header: Прилипающий заголовок Peekaboo с помощью CSS


☺️ Svelte Shy Header: Что такое застенчивый заголовок?

Мне нужно было решение Svelte shy header для добавления на сайт, над которым я работал, и я наткнулся на твит о решении Джейка Арчибальда и Роберта Флэка из команды Google Chromium. Мне нужно было решение для демонстрационного сайта: добавить текст в заголовок, чтобы немного описать настройку. В качестве дополнительной функции для улучшения пользовательского опыта (UX) я хотел, чтобы заголовок появлялся снова, если пользователь снова прокрутит страницу вверх. То есть даже если он уже был на полпути вниз по странице. Идея заключалась в том, чтобы избавить пользователя от необходимости прокручивать страницу до самого верха, чтобы увидеть информацию о настройке сайта.

Я не видел необходимости использовать библиотеку, так как реализация была фантастической. Решение Джейка и Роберта в значительной степени опиралось на современный CSS, и мне было интересно, насколько сильно я могу его упростить. Например, использовать директивы стилей Svelte, привязки размеров элементов и прочее. В общем, кухонная раковина, полный подход Svelte.

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

Оригинальное решение на HTML / CSS / JavaScript

Полное решение Джейка находится на CodePen и использует обычные HTML, CSS и JavaScript. Вот краткое описание:

<div class="header-shifter"></div>
<div class="header">Header</div>
<p>First paragraph</p>
<p>Paragraph</p>
<p>Paragraph</p>
<p>Paragraph</p>
<p>Paragraph</p>
Вход в полноэкранный режим Выход из полноэкранного режима
body {
  margin: 0;
}

.header {
  position: relative;
  background: blue;
  color: white;
  padding: 20px;
}
Войти в полноэкранный режим Выход из полноэкранного режима
// This is adaptation of https://jsbin.com/mamisar/edit?html,css,js,output
// By https://twitter.com/flackrw

const header = document.querySelector('.header');
const headerShifter = document.querySelector('.header-shifter');

header.style.position = 'sticky';
header.style.top = 'calc(var(--computed-height) * -1 - 1px)';
header.style.bottom = 'calc(100% - var(--computed-height))';

function fixHeaderoffset() {
  const { height } = header.getBoundingClientRect();
  header.style.setProperty('--computed-height', height + 'px');

  const y = Math.min(
    header.offsetTop, 
    document.documentElement.scrollHeight - innerHeight - height
  );
  headerShifter.style.height = y + 'px';
  header.style.marginBottom = -y + 'px';
}

addEventListener('scroll', () => fixHeaderoffset());
addEventListener('resize', () => fixHeaderoffset());
fixHeaderoffset();
Войти в полноэкранный режим Выйти из полноэкранного режима

🔫 Svelte Shy Header: План действий по свелтификации

Вот мои первоначальные мысли о процессе Sveltification:

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

Хватит разговоров, пора действовать.

🧱 Svelte Shy Header: Код по ходу

Если вы новичок в Svelte, надеюсь, этот небольшой проект станет для вас легким введением. Вот как вы можете запустить новый проект. Начните с выполнения этих команд в Терминале:

pnpm create svelte@next svelte-shy-header
cd svelte-shy-header
pnpm install
pnpm install @fontsource/playfair-display # installs a font used later for self-hosting
pnpm dev
Войти в полноэкранный режим Выйти из полноэкранного режима

У вас появится несколько вариантов, выберите проект Skeleton и любой другой. Последняя команда запустит dev-сервер и выдаст URL, который вы можете вставить в браузер. Мы создадим или изменим только два файла, поэтому просто вставьте код, когда мы дойдем до этого момента. Также убедитесь, что вы играете, ломаете и ремонтируете вещи, чтобы лучше понять, что они делают!

🏠 Главная страница

Я подумал, почему бы не добавить фоновый CSS-шаблон? Я выбрал шаблон Colorful Stingrays с сайта www.svgbackgrounds.com. Вот полный код для главной страницы (замените существующий контент в src/routes/index.svelte, если вы кодируете вместе с ним):

<script>
    import Header from '$lib/components/Header.svelte';
    import '@fontsource/playfair-display/latin.css';
</script>

<Header />
<main class="container" />

<style>
    :global(body) {
        margin: 0;
        font-family: Playfair Display;
    }
    :global(:after, :before) {
        box-sizing: border-box;
    }
    :global(:root) {
        --font-size-6: 3.052rem;

        --font-weight-bold: 700;

        --max-width-full: 100%;
        --spacing-6: 1.5rem;

        --colour-brand: hsl(19 97% 51%);
        --colour-dark: hsl(345 6% 13%);
    }
    .container {
        height: 500vh;
        width: var(--max-width-full);

        /* CREDIT: https://www.svgbackgrounds.com/ */
        background-color: #3d315b;
        background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='100' viewBox='0 0 600 100'%3E%3Cg stroke='%23FFF' stroke-width='0' stroke-miterlimit='10' %3E%3Ccircle fill='%23FB5607' cx='0' cy='0' r='50'/%3E%3Ccircle fill='%23FC7839' cx='100' cy='0' r='50'/%3E%3Ccircle fill='%23F92A82' cx='200' cy='0' r='50'/%3E%3Ccircle fill='%23F9EA92' cx='300' cy='0' r='50'/%3E%3Ccircle fill='%23F4DA52' cx='400' cy='0' r='50'/%3E%3Ccircle fill='%23EFCA08' cx='500' cy='0' r='50'/%3E%3Ccircle fill='%23FB5607' cx='600' cy='0' r='50'/%3E%3Ccircle cx='-50' cy='50' r='50'/%3E%3Ccircle fill='%23fc6824' cx='50' cy='50' r='50'/%3E%3Ccircle fill='%23ff505a' cx='150' cy='50' r='50'/%3E%3Ccircle fill='%233D315B' cx='250' cy='50' r='50'/%3E%3Ccircle fill='%23f6e273' cx='350' cy='50' r='50'/%3E%3Ccircle fill='%23f1d237' cx='450' cy='50' r='50'/%3E%3Ccircle fill='%23fa9500' cx='550' cy='50' r='50'/%3E%3Ccircle cx='650' cy='50' r='50'/%3E%3Ccircle fill='%23FB5607' cx='0' cy='100' r='50'/%3E%3Ccircle fill='%23FC7839' cx='100' cy='100' r='50'/%3E%3Ccircle fill='%23F92A82' cx='200' cy='100' r='50'/%3E%3Ccircle fill='%23F9EA92' cx='300' cy='100' r='50'/%3E%3Ccircle fill='%23F4DA52' cx='400' cy='100' r='50'/%3E%3Ccircle fill='%23EFCA08' cx='500' cy='100' r='50'/%3E%3Ccircle fill='%23FB5607' cx='600' cy='100' r='50'/%3E%3Ccircle cx='50' cy='150' r='50'/%3E%3Ccircle cx='150' cy='150' r='50'/%3E%3Ccircle cx='250' cy='150' r='50'/%3E%3Ccircle cx='350' cy='150' r='50'/%3E%3Ccircle cx='450' cy='150' r='50'/%3E%3Ccircle cx='550' cy='150' r='50'/%3E%3C/g%3E%3C/svg%3E");
    }
</style>
Войти в полноэкранный режим Выход из полноэкранного режима

Это типичный файл Svelte с тремя секциями: тег script, где мы запускаем код JavaScript, разметка Svelte, затем тег style. Заголовок мы помещаем в собственный файл компонента (импортированный в строке 2). Это облегчает его переработку для использования на других страницах. Сверху вы можете легко создать библиотеку компонентов Svelte, что позволит вам обмениваться кодом между другими проектами Svelte.

🙈 Компонент заголовка Svelte Shy

При кодировании создайте файл src/lib/components/Header.svelte (вам потребуется создать пару новых папок). Именно этот файл мы рассматриваем сейчас. Этот файл в конечном итоге будет содержать три секции, которые мы имеем на главной странице, но мы начнем со средней секции:

<svelte:window on:scroll={fixHeaderOffset} on:resize={fixHeaderOffset} />

<div style:height="{headerShifterHeight}px" class="header-shifter" />
<div
    bind:this={header}
    bind:clientHeight={headerHeight}
    style:margin-bottom="-{headerShifterHeight}px"
    class="header"
>
    <header class="wrapper">☺️ Svelte Shy Header 🙈</header>
</div>
Вход в полноэкранный режим Выход из полноэкранного режима

В строке 1 мы добавляем слушателей событий для событий scroll и resize, но способом Svelte! fixHeaderOffset — это функция, которую мы будем вызывать на эти события. Мы определим ее позже.

Далее, подобно 3, у нас есть header-shifter div. Мы сохраняем оригинальное имя класса, но добавляем:

style:height="{headerShifterHeight}px"
Войти в полноэкранный режим Выход из полноэкранного режима

Как вы уже догадались, здесь мы задаем высоту элемента с помощью CSS. Это директива стиля Svelte. Вместо height вы можете использовать любое обычное CSS-свойство или даже пользовательское CSS-свойство (часто называемое CSS-переменной). headerShifterHeight — это числовая переменная, которую мы определим в теге script. px — это просто добавление ожидаемых единиц для корректного CSS. В качестве альтернативы можно было бы написать что-то вроде этого, используя атрибут style элемента и строки шаблона JavaScript:

<!-- LESS OPTIMAL -->
<div style={`height=${headerShifterHeight}px`} class="header-shifter" />
Войти в полноэкранный режим Выйти из полноэкранного режима

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

Элемент header

Давайте теперь посмотрим на элемент header div (строки 49 выше). Вот он снова:

<div
    bind:this={header}
    bind:clientHeight={headerHeight}
    style:margin-bottom="-{headerShifterHeight}px"
    class="header"
 >
Вход в полноэкранный режим Выйти из полноэкранного режима

Мы только что видели директиву style, и атрибут class не представляет собой ничего нового. Остаются два оператора bind. Первый bind:this={header} — это еще один свелтизм. Он позволяет нам привязать сам элемент к переменной JavaScript header. Это избавляет нас от необходимости писать селектор запроса, когда мы переходим к написанию тега сценария. Это просто синтаксический сахар, делающий код немного чище.

Второй директивой bind мы связываем высоту заголовка с переменной JavaScript headerHeight. Это избавит нас от необходимости вызывать getBoundingClientRect позже в теге script.

💄 Стиль Svelte

Вставьте этот код, если вы кодируете вместе с ним

<style>
    .header-shifter {
        background-color: var(--colour-dark);
    }
    .header {
        --_computed-height: var(--computed-height, 165px);
        position: relative;
        background: var(--colour-dark);
        color: var(--colour-brand);
        padding: var(--spacing-6);
    }
    .wrapper {
        width: var(--max-width-full);
        margin: var(--spacing-6) auto;
        max-width: var(--max-width-full);
        font-size: var(--font-size-6);
        font-weight: var(--font-weight-bold);
        text-align: center;
    }
</style>
Вход в полноэкранный режим Выйти из полноэкранного режима

Мы добавляем немного больше стиля по сравнению с оригинальной версией, но не меняем ничего принципиально. Основным изменением является пользовательское свойство CSS --_computed-height в строке 18. Спецификация пользовательского свойства CSS позволяет нам указать запасное значение в качестве второго аргумента. CSS будет использовать это второе значение, если --computed-height не установлено. Вы заметите, что мы не задаем его нигде в CSS. Как и в оригинальном решении, мы устанавливаем его с помощью JavaScript. Однако, если у пользователя в браузере отключен JavaScript, мы можем положиться на запасное значение, которое мы предоставляем здесь. Это не является строго необходимым (свойство используется только в стилях, добавленных JavaScript), но дает хорошую демонстрацию того, как можно определить значения по умолчанию. За эту технику спасибо Джеффу Ричу.

🐇 Svelte Shy Header: Java Script

Наконец, мы можем увидеть много прицепленный тег script! Еще раз, вставьте его (прямо в начало src/lib/components/Header.svelte), если вы пишете вместе с ним.

<script lang="ts">
    /* This is code is based on an adaptation by https://twitter.com/jaffathecake of
    https://jsbin.com/mamisar/edit?html,css,js,output By https://twitter.com/flackrw 
    */

    import { onMount } from 'svelte';

    let header: HTMLDivElement;
    let headerHeight: number;
    let headerShifterHeight = 0;

    function fixHeaderOffset() {
        header.style.setProperty('--computed-height', `${headerHeight}px`);

        headerShifterHeight =
            Math.min(
                header.offsetTop,
                document.documentElement.scrollHeight - window.innerHeight - headerHeight,
            ) - 1;
    }

    onMount(() => {
        header.style.position = 'sticky';
        header.style.top = 'calc(var(--_computed-height) * -1 - 1px)';
        header.style.bottom = 'calc(100% - var(--_computed-height))';
        fixHeaderOffset();
    });
</script>
Вход в полноэкранный режим Выход из полноэкранного режима

Я должен был упомянуть, что использую TypeScript. Отбросьте lang=ts и аннотации типов (:HTMLDivElement & :number) в строках 13, 20 и 21, если вы выбрали JavaScript.

Давайте посмотрим, что мы имеем. В строках 8 и 9 мы объявляем переменные, которые мы связали в коде шаблона. Затем в строке 10 мы объявляем и инициализируем headerShifterHeight, которую мы также использовали в разметке. Просто используя здесь let, мы делаем переменную реактивной. Это означает, что при ее изменении Svelte автоматически обновит стилевые директивы (а также все остальное связанное), которые мы добавили ранее.

Функция fixHeaderOffset в оригинальной реализации осталась, хотя у нас есть несколько отличий. Мы избавились от вызова getBoundingClientRect для получения высоты заголовка, так как теперь у нас есть значение, привязанное к headerHeight в Svelte. Мы переименовали y в headerShifterHeight, просто чтобы код шаблона был немного понятнее. Затем, помните, что мы используем директивы стиля для установки высоты элемента header-shifter и нижнего поля элемента header, поэтому удалили эти две строки.

SvelteonMount

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

Мы задаем здесь стилевые реквизиты CSS, вместо того чтобы использовать стилевые директивы, просто потому что они не понадобятся, если у пользователя отключен JavaScript. В данном случае нам нужен обычный заголовок postion: relative, а не sticky, управляемый в JavaScript. Поскольку функция onMount не будет загружаться при отключенном JavaScript, CSS переопределение здесь для header.style.position будет установлено только при включенном JavaScript.

CSS-свойства top и bottom актуальны только при включенном JavaScript (в противном случае мы используем относительное позиционирование). Учитывая это, мы устанавливаем эти два свойства в onMount, а не используем стилевые директивы. Обратите внимание, что мы используем --_computed-height вместо --computed-height. Это потому, что, как мы уже упоминали выше, первая будет иметь значение по умолчанию, доступное до того, как мы впервые вычислим и установим --computed-height.

Наконец, мы поместили вызов fixHeaderOffset в onMount, потому что нам нужно получить доступ к связанным переменным JavaScript (header и headerHeight) при вызове функции. Они доступны только после того, как мы смонтируем компонент. Поэтому размещение начального вызова fixHeaderOffset здесь позволяет избежать вызова функции, когда эти переменные еще не определены.

🙌🏽 Svelte Shy Header: Завершение

В этом посте Svelte shy header. Мы рассмотрели некоторые полезные методы Svelte и то, как они связаны с теми, которые вы можете увидеть на обычных HTML / CSS / JavaScript сайтах. В частности, мы затронули следующие вопросы:

  • как использовать директивы стилей Svelte для стилизации компонентов и когда другой подход может быть предпочтительнее,
  • полный код для реализации Svelte shy header в качестве многоразового компонента,
  • как привязать размеры компонента к переменным JavaScript с помощью Svelte.

В качестве следующего шага вы можете изучить одно из учебных пособий, чтобы узнать больше о Svelte. Если вы уже знаете основы, попробуйте также добавить этот палочный заголовок в библиотеку компонентов Svelte. Возможно, вы также захотите вывести пользовательские свойства CSS на новый уровень, задавая их в действиях Svelte. Дайте мне знать, что вы создадите в итоге. Вы можете оставить комментарий ниже или связаться со мной в Element, а также в Twitter @mention.

Вы можете увидеть полный код этого проекта Svelte shy header во всей его красе в репозитории Rodney Lab Git Hub.

🙏🏽 Svelte Shy Header: Обратная связь

Если вы нашли этот пост полезным, смотрите ссылки ниже для дальнейшего связанного контента на этом сайте. Я надеюсь, что вы узнали что-то новое из этого видео. Дайте мне знать, есть ли способы улучшить его. Я надеюсь, что вы будете использовать код или стартер в своих собственных проектах. Не забудьте поделиться своей работой в Twitter, упомянув меня, чтобы я мог увидеть, что у вас получилось. И наконец, не забудьте сообщить мне о своих идеях относительно других коротких видео, которые вы хотели бы увидеть. О том, как связаться со мной, читайте ниже. Если вы нашли этот пост полезным, даже если вы можете позволить себе лишь крошечный вклад, пожалуйста, поддержите меня через Buy me a Coffee.

Наконец, не стесняйтесь поделиться этим постом в своих социальных сетях для всех ваших подписчиков, которые найдут его полезным. Помимо того, что вы можете оставить комментарий ниже, вы можете связаться со мной через @askRodney в Twitter, а также askRodney в Telegram. Также смотрите другие способы связаться с Rodney Lab. Я регулярно пишу о SvelteKit, а также о поисковой оптимизации и других темах. Также подпишитесь на рассылку новостей, чтобы быть в курсе наших последних проектов.

Оцените статью
devanswers.ru
Добавить комментарий