Это простое руководство, которое расскажет о процессе разработки для https://keidyz.github.io/activity-generator/ и охватит такие основы, как:

  • Использование Git (будут рассмотрены только упрощенные основы, достаточные для размещения вашего кода в репозитории. Ветвление, CI, PR, этикет коммитов и передовой опыт будут в другой статье)
  • Создание html-стороны
  • Стилизация html с помощью css
  • Написание кода javascript, чтобы сделать его интерактивным
  • Внедрение определенных методологий и передовой практики
  • Адаптивный дизайн, чтобы сделать веб-приложение удобным для использования на экранах разного размера.
  • Размещение веб-приложения на страницах github

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

Обратите внимание, что это веб-приложение не будет иметь API и является чисто внешним интерфейсом.

Это выгодно для новичков из-за бесплатного внешнего хостинга github.

Репозиторий итоговых результатов: https://github.com/keidyz/activity-generator

ПРИМЕЧАНИЕ. Это руководство предназначено для начинающих, но я буду добавлять небольшие кусочки информации об определенных отраслевых стандартах и ​​тому подобном. В основном они будут сопровождаться внешними ссылками, чтобы более опытные читатели могли учиться отдельно.

Начало — установка git:

ПРИМЕЧАНИЕ. Вы можете пропустить это, если не собираетесь размещать свое веб-приложение на github

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

Вот отличное руководство по установке git в вашей системе: https://github.com/git-guides/install-git

После установки вы можете открыть терминал и ввести git -v

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

Начало — Установка редактора кода:

ПРИМЕЧАНИЕ. Вы можете пропустить это

Редактор кода упрощает изменение нескольких файлов с разным синтаксисом.

Мне лично нравится https://code.visualstudio.com/, но блокнот тоже должен работать.

Шаг 1 — Создание репозитория вашего проекта:

ПРИМЕЧАНИЕ. Вы можете пропустить это, если не собираетесь размещать свое веб-приложение на github

Репозиторий кода — это просто место в Интернете, где хранится ваш код.

Думайте об этом как о папке на рабочем столе, которую вы загрузили в Интернет.

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

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

Для начала перейдите на https://github.com/ и создайте/войдите в свою учетную запись.

Оттуда вы сможете увидеть значок «плюс» в правом верхнем углу, который при нажатии должен показать вам кнопку с надписью «Новый репозиторий».

Это покажет вам форму для создания нового репозитория.

Вы можете делать с формой все, что хотите, но если вы являетесь бесплатным пользователем, обязательно сделайте репозиторий «Общедоступным» — таким образом, у вас будет доступ к бесплатному хостингу через страницы GitHub.

После нажатия кнопки «Создать репозиторий» у вас должен появиться собственный репозиторий.

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

Шаг 2 — Клонирование репозитория в вашу локальную систему

ПРИМЕЧАНИЕ. Вы можете пропустить это, если не собираетесь размещать свое веб-приложение на github

Поднимите терминал и перейдите в папку, в которой вы хотите, чтобы была папка вашего проекта.

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

Пользователи macOS и Linux, скорее всего, будут иметь такой же вывод и структуру каталогов, как показано ниже.

Пользователи Windows могут иметь другую структуру каталогов вместе с другими командами, но все должно быть в порядке, если вы можете клонировать репозиторий в свою систему, используя git clone

Клонированный репозиторий — это просто папка, которую вы также можете найти с помощью системного поиска / проводника.

Шаг 3 — Внесение небольших изменений и загрузка в репозиторий онлайн

ПРИМЕЧАНИЕ. Вы можете пропустить это, если не собираетесь размещать свое веб-приложение на github

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

Создайте файл sample.txt в папке и введите все, что хотите.

Поднимите терминал и перейдите к клонированной папке.

VSCode имеет встроенный терминал, который вы можете вызвать с помощью cmd+j для пользователей macOS и ctrl+j linux (возможно, то же самое для пользователей Windows).

По умолчанию терминал vscode использует текущий каталог в качестве отправной точки, поэтому нет необходимости переходить к какой-либо другой папке.

ПРИМЕЧАНИЕ. Передовой опыт работы с git игнорируется и здесь не обсуждается. Единственная цель — перенести ваши локальные изменения в репозиторий на github.

Это ни в коем случае не учебник по git, и здесь все слишком упрощено.

Известные команды, используемые на картинке ниже:

  • git status: отображает состояние рабочего каталога. На картинке мы видим готовый к добавлению и фиксации файл sample.txt.
  • git add .: Добавляет файлы в промежуточную область, чтобы их можно было зафиксировать. . — это подстановочный знак, означающий «Добавить все файлы в рабочем каталоге в промежуточную область».
  • git commit -m : создает моментальный снимок промежуточной области для подготовки к отправке этих изменений в удаленный репозиторий.
  • git push : Обновляет удаленный репозиторий коммитами, которые есть у вас в локальном

После успешной отправки ваш удаленный репозиторий должен выглядеть так.

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

Шаг 4 — Создание HTML-файла

Сначала мы удалим файл sample.txt, который мы создали на предыдущем шаге, так как он нам на самом деле не нужен.

Для этого урока нам нужны только три файла:

  • html файл — структура/кости приложения
  • файл css — стиль/оболочка приложения
  • файл javascript — функциональность/мышцы приложения

Для начала мы создадим файл index.html в рабочем каталоге и вставим в него следующее содержимое:

<!DOCTYPE html>
<html>
    <head>
        <meta name="description" content="An app that generates a random activity for you"/>
        <title>Activity Generator</title>
    </head>
    <body>
        <div>Activity Generator</div>
    </body>
</html>

После этого открытие файла index.html в браузере (я использую Chrome) должно показать следующее.

Мы настроили самый минимум, и вот как мы можем просмотреть его в браузере. Давайте теперь добавим в тело нашего приложения

<!DOCTYPE html>
<html>
    <head>
        <meta name="description" content="An app that generates a random activity for you"/>
        <title>Activity Generator</title>
    </head>
    <body>
        <div class="container">
            <h1 class="container__title">Activity Generator</h1>
            <div class="container__activity"></div>
            <div class="container__main">
                <button class="container__main__generate-button">Generate</button>
            </div>
        </div>
    </body>
</html>

Обратите внимание, что элементы не имеют идентификатора, но имеют имена классов в определенном формате — это потому, что в этом руководстве мы будем использовать методологию БЭМ для идентификации наших элементов.

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

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

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

Существует множество методологий css, и у каждой из них есть особенности и ситуации, в которых они могут быть лучше других.

Я лично предпочитаю BEM, потому что он помогает сделать элементы легко идентифицируемыми, а также легко устраняет конфликты имен и стилей.

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

На данный момент приложение должно выглядеть так.

Теперь структура веб-приложения завершена, и теперь мы можем приступить к созданию стиля.

Шаг 4 — Создание и привязка таблицы стилей к index.html

Создайте файл index.css в рабочем каталоге и вставьте в него следующее содержимое:

div {
    background-color: red;
}

Это говорит о том, что цвет фона всех элементов div будет красным.

Если вы откроете index.html в браузере — вы заметите, что ничего не изменилось — это потому, что мы должны связать index.css с index.html, используя <link rel="stylesheet" href="index.css">, который мы добавим ниже тег <head>

index.html теперь должен выглядеть так

<!DOCTYPE html>
<html>
    <head>
        <meta name="description" content="An app that generates a random activity for you"/>
        <title>Activity Generator</title>
        <link rel="stylesheet" href="index.css">
    </head>
    <body>
        <div class="container">
            <h1 class="container__title">Activity Generator</h1>
            <div class="container__activity"></div>
            <div class="container__main">
                <button class="container__main__generate-button">Generate</button>
            </div>
        </div>
    </body>
</html>

Теперь веб-приложение должно выглядеть так

Очевидно, это не тот стиль, который нам нужен, но теперь мы по крайней мере убедились, что index.css теперь связан с index.html.

Шаг 5 — Выбор цветов и шрифтов

Лично мне нравится посещать сайты типа coolors и выбирать там цветовые палитры.

Для этого урока я использовал первый и третий цвета этой палитры.

Просто запомните шестнадцатеричный код используемых цветов, в данном уроке это #edf6f9 и #006d77.

Что касается шрифтов, мне нравится посещать Шрифты Google и выбирать там шрифты.

В этом уроке используются Archivo black и Roboto Regular 400.

Чтобы иметь возможность использовать выбранные шрифты, просто скопируйте теги ссылок, предоставленные шрифтом Google, и вставьте их как дочерние теги заголовка в index.html.

На этом этапе index.html должен выглядеть следующим образом:

<!DOCTYPE html>
<html>
    <head>
        <meta name="description" content="An app that generates a random activity for you"/>
        <title>Activity Generator</title>
        <link rel="preconnect" href="https://fonts.googleapis.com">
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
        <link href="https://fonts.googleapis.com/css2?family=Archivo+Black&family=Roboto&display=swap" rel="stylesheet">
        <link rel="stylesheet" href="index.css">
    </head>
    <body>
        <div class="container">
            <h1 class="container__title">Activity Generator</h1>
            <div class="container__activity"></div>
            <div class="container__main">
                <button class="container__main__generate-button">Generate</button>
            </div>
        </div>
    </body>
</html>

Шаг 6 — Фактический стиль

Очистите содержимое index.css.

Теперь мы начнем добавлять к нему следующие блоки

body {
    font-family: 'Roboto', sans-serif;
    background-color: #edf6f9;
    color: #006d77;
    margin: 0px;
}

Если вы посмотрите на index.html, все основные элементы находятся внутри тега ‹body›. Приведенный выше стиль в основном объявляет стиль всех элементов внутри тега body. margin: 0px удаляет поле по умолчанию, которое некоторые браузеры применяют к тегу body.

.container {
    min-height: 100vh;
    min-height: -moz-available;
    min-height: -webkit-fill-available;
    min-height: fill-available;
    padding: 15px;
}

Чтобы выбрать класс для стиля, все, что нужно сделать, это добавить . в начале. В данном случае мы стилизуем класс контейнера.

min-height объявляется несколько раз для разных браузеров, при этом min-height: 100vh является запасным вариантом на тот случай, если браузер, в котором запущено это приложение, не может понять, что означает fill-available, -webkit-fill-available и -moz-available.

Минимальная высота здесь в основном говорит «занять всю высоту области просмотра».

Почему бы просто не использовать min-height: 100vh?

Потому что хотя 100vh означает 100% высоты области просмотра, во многих случаях нам это не обязательно нужно.

Возьмите это, например:

Слева мы видим, что он действительно занимает 100% высоты области просмотра, но справа показана панель браузера — она занимает часть экрана, но поскольку высота страницы равна всей области просмотра устройства. , это приводит к появлению ненужной полосы прокрутки/эффекта прокрутки.

Вот почему заполняемость обычно предпочтительнее 100vh.

Остальные стили очень продуманы, и в целом index.css должен иметь следующее содержимое:

body {
    font-family: 'Roboto', sans-serif;
    background-color: #edf6f9;
    color: #006d77;
    margin: 0px;
}

.container {
    min-height: 100vh;
    min-height: -moz-available;
    min-height: -webkit-fill-available;
    min-height: fill-available;
    padding: 15px;
}

.container__title {
    font-family: 'Archivo Black', sans-serif;
    text-align: center;
    font-size: 8vw;
    margin: 100px 0;
}

.container__main {
    display: flex;
    justify-content: center;
}

.container__main__generate-button {
    background-color: #006d77;
    border: 0;
    color: #edf6f9;
    padding: 10px 20px;
    border-radius: 10px;
    font-size: 3vw;
}

Вы можете заметить, что font-size использует vw — обычно это делается для того, чтобы шрифты масштабировались вместе с шириной экрана устройства.

Вы также можете заметить, что container__activity имеет огромную минимальную высоту вместе с полем. Используется минимальная высота

В итоге ваше приложение должно выглядеть так

Теперь он ближе к тому стилю, который нам нужен.

Шаг 6 — Ванильный JavaScript

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

Создайте файл index.js и скопируйте в него следующее содержимое.

document.querySelector(".container__main__generate-button").addEventListener("click", console.log)

В приведенной выше строке мы выбираем элемент с классом container__main__generate-button и добавляем прослушиватель событий к его событию click.

При каждом щелчке он создает console.log и передает определенные данные в качестве своих аргументов.

Мы можем проверить это, открыв консоль браузера, которая находится в инструментах разработчика. Пользователи macOS Chrome могут просто нажать cmd+option+i, чтобы отобразить инструменты разработчика.

Но перед этим, как и в случае с index.css, мы должны связать index.js с index.html.

Мы можем сделать это, добавив <script type=”text/javascript” src=”index.js”></script> в качестве дочернего элемента <head> или <body>.

Элемент head загружается перед элементом body, и наш javascript-код будет обращаться к элементам внутри элемента body, поэтому лучше поместить тег script в элемент body, чтобы мы могли убедиться, что эти элементы уже существуют при загрузке скрипта.

Новый index.html должен выглядеть следующим образом.

<!DOCTYPE html>
<html>
    <head>
        <meta name="description" content="An app that generates a random activity for you"/>
        <title>Activity Generator</title>
        <link rel="preconnect" href="https://fonts.googleapis.com">
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
        <link href="https://fonts.googleapis.com/css2?family=Archivo+Black&family=Roboto&display=swap" rel="stylesheet">
        <link rel="stylesheet" href="index.css">
    </head>
    <body>
        <div class="container">
            <h1 class="container__title">Activity Generator</h1>
            <div class="container__activity"></div>
            <div class="container__main">
                <button class="container__main__generate-button">Generate</button>
            </div>
        </div>
        <script type="text/javascript" src="index.js"></script>
    </body>
</html>

Теперь приложение должно отображать данные в окне консоли, когда пользователь нажимает кнопку «Создать».

Написанный нами javascript-код в какой-то мере функционирует, но давайте заменим его на более удобный в сопровождении.

const generateButtonElement = document.querySelector(".container__main__generate-button")
const activityTextElement = document.querySelector(".container__activity")

const handleGenerateButtonClick = () => {
    activityTextElement.textContent = Math.random()
    console.log('clicked')
}

generateButtonElement.addEventListener("click", handleGenerateButtonClick)

В приведенном выше коде мы разделили результаты document.querySelector на их собственные переменные — таким образом, мы можем легко повторно использовать эти элементы в будущем, и в случае изменения имени их класса нам нужно будет изменить его только в одно место.

console.log также был заменен функцией handleGenerateButtonClick, которая изменяет текст .container__activity на некоторую случайную плавающую точку при каждом нажатии кнопки.

Теперь приложение должно выглядеть следующим образом

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

Далее мы хотим фактически генерировать действия.

Наша деятельность варьируется от

  • Бегать 5 минут
  • Назовите 5 стран, названия которых начинаются на букву Г.
  • Скажи «корова» 26 раз.

Обратите внимание, как мы можем повторно использовать определенные предложения, просто заменяя определенные цифры, символы и буквы?

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

// declare constraints and constants
const SMALL_NUMBER_MAX = 5
const SMALL_NUMBER_MIN = 2
const MEDIUM_NUMBER_MAX = 10
const MEDIUM_NUMBER_MIN = 3
const LARGE_NUMBER_MAX = 30
const LARGE_NUMBER_MIN = 20
const ANIMALS = ["dog", "cat", "butterfly", "bat", "grasshopper", "chicken", "pig", "cow", "snake", "eagle",
                "lion", "puma", "hippo", "monkey", "ant", "rat", "alligator"]

// Math.floor(Math.random() * ((SMALL_NUMBER_MAX - SMALL_NUMBER_MIN) + 1)) + SMALL_NUMBER_MIN
// ^ basically means to generate a number between (and including) SMALL_NUMBER_MIN and SMALL_NUMBER_MAX
// we plan to use expressions by looking for "text" in a string
// and calling fn() to replace it
// ex:
// "Run around for small-number minutes"
// our code will later target small-number and replace it with the results
// of expressions.smallNumber.fn() which should be a number 2~5
const expressions = {
    smallNumber: {
        text: 'small-number',
        fn: () => Math.floor(Math.random() * ((SMALL_NUMBER_MAX - SMALL_NUMBER_MIN) + 1)) + SMALL_NUMBER_MIN,
    },
    mediumNumber: {
        text: 'medium-number',
        fn: () => Math.floor(Math.random() * ((MEDIUM_NUMBER_MAX - MEDIUM_NUMBER_MIN) + 1)) + MEDIUM_NUMBER_MIN,
    },
    largeNumber: {
        text: 'large-number',
        fn: () => Math.floor(Math.random() * ((LARGE_NUMBER_MAX - LARGE_NUMBER_MIN) + 1)) + LARGE_NUMBER_MIN,
    },
    randomCapitalLetter: {
        text: 'random-capital-letter',
        fn: () => String.fromCharCode(65+Math.floor(Math.random() * 26)),
    },
    randomAnimal: {
        text: 'random-animal',
        fn: () => {
            const animalIndex = Math.floor(Math.random() * ANIMALS.length)
            return ANIMALS[animalIndex]
        }
    }
};

// `Run around for ${expressions.smallNumber.text} minutes`,
// because of string interpolation, the above will become 
// `Run around for small-number minutes`
// We will then later read the string and replace "small-number"
// with an actual small number

// why do this and not just do "Run around for small-number minutes"?
// it's because typing in the string small-number is prone to typos
// and the code won't know it's a typo since no error has occurred
// also, using expressions.smallNumber.text means that if you want
// to change the "small-number" string to "tiny-number" then all
// you have to do is change it in one place instead of changing
// it in every item of the activities array

// NOTE: Activities must take a maximum of 5 minutes to accomplish
const activities = [
    `Run around for ${expressions.smallNumber.text} minutes`,
    `Jog for ${expressions.smallNumber.text} minutes`,
    `Walk around for ${expressions.smallNumber.text} minutes`,
    `Name ${expressions.mediumNumber.text} yogurt flavors`,
    `Jump ${expressions.mediumNumber.text} times`,
    `Name ${expressions.mediumNumber.text} countries that start with the letter ${expressions.randomCapitalLetter.text}`,
    `Remember the weather ${expressions.smallNumber.text} days ago`,
    `Name ${expressions.smallNumber.text} people you've most recently interacted with`,
    `Roll on the floor for ${expressions.smallNumber.text} minutes`,
    `Gather all your laundry and place them in the laundry basket`,
    `Picture an animal that's ${expressions.randomAnimal.text}-${expressions.randomAnimal.text}`,
    `Say "${expressions.randomAnimal.text}" ${expressions.largeNumber.text} times`,
]

// Core code for choosing the random activity
let activityIndex = -1
const generateActivity = () => {
    let newActivityIndex = Math.floor(Math.random() * activities.length)
    // the while loop is responsible for making sure the new random activity
    // is not identical to the previous activity
    while(newActivityIndex === activityIndex) {
        newActivityIndex = Math.floor(Math.random() * activities.length)
    }
    activityIndex = newActivityIndex
    // the following line is responsible for replacing strings such as
    // "small-number" -> 3 or 4 and such
    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
    return Object.values(expressions).reduce((acc, {text: activityKey, fn: activityFn}) => {
        return acc.replaceAll(activityKey, activityFn)
    }, activities[activityIndex])
}

const generateButtonElement = document.querySelector(".container__main__generate-button")
const activityTextElement = document.querySelector(".container__activity")

const handleGenerateButtonClick = () => {
    // use the result of generateActivity() as the text content
    activityTextElement.textContent = generateActivity()
}

generateButtonElement.addEventListener("click", handleGenerateButtonClick)

Теперь приложение должно выглядеть

Мы почти закончили, осталось изменить стиль.

Шаг 7 — Настройка стиля, чтобы сделать вещи красивее

Чтобы исправить стиль текста активности, мы можем просто добавить следующее в index.css

.container__activity {
    text-align: center;
    font-size: 5vw;
    min-height: 12vw;
    margin: 100px 0;
}

.container__activity--visible {
    opacity: 1;
    transition: opacity 0.1s linear;
}

.container__activity--hidden {
    opacity: 0;
    transition: opacity 0.2s linear;
}

Обратите внимание, что у нас есть два новых класса container__activity — visible и container__activity — hidden. Эти классы не перечислены в index.html, но если мы добавим container__activity — hidden к элементу активности, он будет медленно исчезать, а добавление container__activity — visible к элементу заставит элемент медленно исчезать.

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

Для этого нам просто нужно добавить пару новых функций и заменить handleGenerateButtonClick на следующее в нашем index.js.

const hideActivityText = () => {
    activityTextElement.classList.remove("container__activity--visible")
    activityTextElement.classList.add("container__activity--hidden")
}

const showActivityText = () => {
    activityTextElement.classList.remove("container__activity--hidden")
    activityTextElement.classList.add("container__activity--visible")
}

const handleGenerateButtonClick = () => {
    // fade out the activity element
    hideActivityText()
    window.setTimeout(() => {
        // everything in here will run 200ms after clicking the button
        activityTextElement.textContent = generateActivity()
        // fade in the activity element
        showActivityText()
    }, 200)
}

hideActivityText и showActivityText — это идемпотентные функции, отвечающие за переключение классов container__activity — visible и container__activity — hidden.

Идемпотентные функции — это функции, которые дают одинаковый эффект даже при двойном вызове.

Например, вызов hideActivityText() приведет к тому, что текстовый элемент активности исчезнет, ​​а повторный вызов той же функции больше ничего не сделает.

Теперь у нас есть следующий вывод

Шаг 7 — Использование переменных css

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

Представьте, что вы используете шестнадцатеричный цвет #edf6f9 более чем в 30 определенных элементах, а затем понимаете, что хотите использовать вместо него другой цвет. Это означало бы поиск всех экземпляров #edf6f9 и замену их везде.

Чтобы сделать это проще, вы можете использовать переменные css.

Мы добавим следующее в index.css

:root {
    --primary-color: #edf6f9;
    --secondary-color: #006d77;
}

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

С переменными css замена#edf6f9 на другой шестнадцатеричный означает замену только в одной строке.

Теперь мы можем заменить все значения свойства #edf6f9 на var( — primary-color) то же самое с #006d77, которое можно заменить на var( — secondary-color)

index.css теперь должен выглядеть следующим образом

:root {
    --primary-color: #edf6f9;
    --secondary-color: #006d77;
}

body {
    font-family: 'Roboto', sans-serif;
    background-color: var(--primary-color);
    color: var(--secondary-color);
    margin: 0px;
}

.container {
    min-height: 100vh;
    min-height: -moz-available;
    min-height: -webkit-fill-available;
    min-height: fill-available;
    padding: 15px;
}

.container__title {
    font-family: 'Archivo Black', sans-serif;
    text-align: center;
    font-size: 8vw;
    margin: 100px 0;
}

.container__activity {
    text-align: center;
    font-size: 5vw;
    min-height: 12vw;
    margin: 100px 0;
}

.container__activity--visible {
    opacity: 1;
    transition: opacity 0.1s linear;
}

.container__activity--hidden {
    opacity: 0;
    transition: opacity 0.2s linear;
}

.container__main {
    display: flex;
    justify-content: center;
}

.container__main__generate-button {
    background-color: var(--secondary-color);
    border: 0;
    color: var(--primary-color);
    padding: 10px 20px;
    border-radius: 10px;
    font-size: 3vw;
}

Шаг 8 — Адаптивный дизайн

Мы в основном закончили, за исключением того, что наше приложение выглядит странно на других экранах.

Адаптивный дизайн означает, что дизайн должен выглядеть (в разумных пределах) хорошо на разных экранах.

Эта часть немного проще для нас, потому что мы использовали динамические единицы css (vw) для многих наших элементов, что означает, что многие наши элементы масштабируются с шириной области просмотра устройства, но мы не хотим, чтобы крошечный текст был включен. малюсенький экран.

Вот как это выглядит на iPhone 12 Pro.

Первым шагом к реализации адаптивного дизайна является добавление метатега области просмотра в качестве дочернего элемента тега ‹head›.

<meta
  name="viewport"
  content="width=device-width, initial-scale=1"
/>

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

width=device-width устанавливает ширину страницы равной ширине экрана устройства

initial-scale=1.0 устанавливает начальный уровень масштабирования при первой загрузке страницы браузером

Сейчас это изменение мало что дает, но мы можем добавить следующие медиа-запросы в index.css.

@media only screen and (max-width: 700px) {
    .container__title {
        font-size: 9vw;
    }
    .container__activity {
        font-size: 6vw;
        min-height: 14vw;
    }
    .container__main__generate-button {
        font-size: 4vw;
    }
}

@media only screen and (max-width: 400px) {
    .container__title {
        font-size: 12vw;
    }
    .container__activity {
        font-size: 8vw;
        min-height: 30vw;
    }
    .container__main__generate-button {
        font-size: 6vw;
    }
}

Первый медиа-запрос будет вызываться, когда ширина устройства ниже 700 пикселей, а второй будет вызываться, когда ширина устройства ниже 400 пикселей.

Вот как теперь должна выглядеть линия на iPhone 12 Pro.

Вот до

Вот после

Шаг 9 — Размещение на страницах github

Как и в шаге 3, мы должны отправить все наши изменения в наш удаленный репозиторий.

После отправки изменений новые файлы и изменения должны появиться в удаленном репозитории.

Включить страницы github.

После этого начнется сборка.

После завершения сборки URL-адрес вашей страницы должен быть доступен для просмотра в задании развертывания.

Теперь вы успешно создали и разместили веб-приложение с использованием ванильного javascript 🥳.