Я думаю, всем нам иногда бывает интересно, как тот или иной человек развивался и как начинал путь. Когда объектом интереса стану я, мне бы хотелось, чтобы это было реализовано удобно для всех и с доступностью прямо с сайта.
Именно для этого и создан данный раздел на сайте. Вы можете, во-первых, по дням отследить, как и что я изучал, с самого первого дня развития в формате ленты. Во-вторых, вы можете посмотреть, как в тот или иной день выглядел сайт. На момент создания этой страницы он представлял из себя голый HTML-документ — однако кто знает, каким будет сайт в будущем? =)
Обучение по дням
Дата публикации:
Дни 10—11: ЕГЭ, завершение работы с кнопками и формами и ещё немного лоска с помощью CSS
Так что там с ЕГЭ?
С ЕГЭ всё отлично!
Предмет
Количество баллов
Русский язык
61
Математика (профильная)
58
Информатика
20*
* На момент написания статьи официального результата не было; но я сделал только 3 задания, и 20 — это самый лучший расклад. xD
У некоторых может возникнуть справедливый вопрос: и как же это всё отлично, если информатика де-факто не сдана, а по другим двум предметам тоже мало баллов? Дело в том, что я иду в колледж и не иду в вуз. Мне нужен только аттестат, так что я не переживаю. В колледжах не спрашивают баллы ЕГЭ. 😝 Дальше мне нужно будет получить медицинское заключение для колледжа — 3517 ₽, на минуточку! — после чего смогу подавать документы.
Больше кнопок и форм богу кнопок и форм!
Да… возвращаемся к ВОТ ЭТИМ ВОТ. 😩
Бо-о-оже, это было ужасно! Пока запомнишь, как всё это работает, нужно будет это не один раз повторить. Впрочем, никто ничего не запоминает раз и навсегда; в пору интернета всегда есть возможность проверить и уточнить, верно? ;)
Обновление в CSS и немного в доступности
Сегодня я освоил max-width, line-height, padding и ещё некоторую красоту, которая позволила сделать сайт лучше. :> Текст больше не растягивается на всю страницу, а аккуратно располагается в центре; также он стал побольше, а межстрочный интервал приобрёл более удобочитаемый вид. 🌸
По доступности: прогнав свой сайт через Google Lighthouse, я понял, что в моментах, где я даю описание картинок и ссылки на страницы картинок в Pexels, люди со скринридерами получают набор ссылок, которые звучат абсолютно одинаково. (Они слышат что-то вроде «копирайт, [имя сделавших фотографию] на „ссылка: Pexels“». Получается какая-то каша: предлог «на» смешивается со словом «ссылка», а слово Pexels не даёт много информации.) Было придумано изящное и более корректное с точки зрения семантики решение: у тега <a> можно задавать название с помощью aria-label. Теперь человек будет слышать «копирайт, [имя сделавших фотографию]; „ссылка: Часовня тишины на Pexels“». Предлог «на» я убрал от людей без скринридеров, заменив его на длинное тире — выглядит оно даже более профессионально. B)
День 9: кнопки, формы и прочие ужасы, которые за один раз не запомнишь…
Дата публикации:
Кнопки и формы (будь они неладны!)
Всех приветствую! Хотелось бы выйти на режим ежедневных коммитов (мечтать не вредно! 😝), поэтому активно учусь дальше.
Сегодня, после наведения финального лоска в CSS — да, Джеминай мне всё предлагает и предлагает кучу симпатичного, а я всё не против и не против, — я наконец-то возвращаюсь к курсу от FreeCodeCamp по HTML! Следующая тема… о-о-ой, формы и кнопки… Я помню, как я был поражён количеству полученной информации, когда у меня была первая и менее публичная попытка в веб-разработку с курсом уже от BroCode. Надеюсь, в этот раз будет попроще. Хотя длина этого урока на таймлайне не вызывает доверия. 🥲 Попробуем?..
Важное примечание: все формы липовые и мне не приходят на данный момент!
Окей, чат, завтра мне на экзамен последний (конечно, я ничего не знаю и ничего не напишу), так что пойду уже спать. git push origin main и до завтра! 🍓
Дни 5—8: внезапная оптимизация картинок, первые шажки в CSS и ИИ
Дата публикации:
Доведения до ума раздела об истории развития сайта
Что? Да! Я решил, что такой раздел должен быть прямо на сайте с возможностью взглянуть, как всё выглядело в тот или иной день. Вы, вероятно, прямо с неё читаете данный текст. Здесь будут история по дням изучения и история в виде полноценных снапшотов — копий сайта за тот или иной день. Они находятся в самом низу. Внизу этих снапшотов была добавлена подпись о том, что это архивная версия сайта, и кнопки перехода от одного снапшота к следующему и предыдущему — Джеминай мне помог сделать это покрасивее.:>
Желание публиковаться на GitHub
Где-то 4 дня назад я решил, что было бы круто разместить свой сайт на гитхабе, потому что он позволяет опубликовать сайт бесплатно, даже не оплачивая никакого хостинга. После этого начинается самое интересное…
Во-первых, надо выбрать лицензию. ИИ предлагает как универсальный вариант лицензию от MIT, но я вспоминаю, что слышал легенды про лицензии GNU и восхищался. Погуглив, я решил, что буду брать AGPLv3. Она хороша тем, что любой человек, который решит работать с моим кодом, будет обязан опубликовать все свои изменения; иначе я буду иметь право его засудить. 🫦 Вот она: свобода кода любой ценой!
Но с такой лицензией я дважды задумался над картинками, которые были у меня на сайте, а именно шуточные скриншоты из GTA в контексте мест, которые мне бы хотелось посетить. Уж не знаю, мог бы я в будущем заинтересовать Rockstar, но, если я правильно понимаю, это одна из компаний с вредными юристами, поэтому я решил не рисковать и брать свободные для распространения фотографии с Pexels. Отлично, с интеллектуальной собственностью — будь оно проклята! — мы разобрались. Теперь можно просто вставить картинки, верно?.. Ну… не совсем.
Оптимизация размера изображений
Итак, загружать оригинал в 2 МиБ — это неприемлемо по нынешним веб-стандартам. Я поговорил об этом с Чатом — ChatGPT, — и тот предложил мне bash-скрипт для сжатия. И после этого я упал в кроличью нору… Я думал расписать подробно, как и насколько разные ИИ мне помогли в создании скрипта, но мне кажется, что это будет излишним. Больше всего мне помогли Джеминай и Клод; первую заготовку сделал Чат, Грок тоже внёс пару правок, но начал слишком быстро просить денег и ограничивая наш чат на 8 часов. Клод выглядел самым способным по коду, хотя Джеминай не отставал (по крайней мере в работе с этим конкретным bash-скриптом) и был разве что подружелюбнее. Но! С Клодом был интересный диалог:
— У меня опять горят глаза насчёт картинок. 🫦 Как это можно реализовать в нашем имеющемся скрипте? 🤔
— Нет. 😄
Серьёзно — сначала напиши хоть одну страницу. Ты не знаешь ещё какие размеры тебе нужны, как картинки будут вписаны в макет, какие брейкпоинты ты выберешь. Дописывать скрипт под размеры которые ты не знаешь — это работа вслепую.
Когда сделаешь первый макет и увидишь что картинка на мобильном занимает 480px, а на десктопе 1200px — вот тогда приходи, добавим за пять минут.
Впервые ИИ мне отказал! Дальше я всё же смог его убедить мне помочь, сказав, что у меня уже есть несколько страниц, но это было интересно. А отказ, если честно, по делу. Как бы то ни было, теперь у меня есть скрипт, который при первом запуске спрашивает, в где хранится директория img, а при втором уточняет, в какую поддиректорию загружать конкретные файлы. Дальше он спрашивает, насколько агрессивную стратегию сжатия использовать; после этого он делает своё дело, сохраняя в директорию /original оригинал изображения, а на директорию выше кидает 7 файлов (каждый меньше 250 КиБ): AVIF и WEBP для экранов смартфонов (640 px), для экранов маленьких ноутбуков и планшетов (1200 px) и для десктопа (1920 px) и JPEG (чтобы в случае чего загрузилось даже на древнейших девайсах), давая в терминале сразу вывод для HTML-файла.
Раз уж такое дело, неудобно будет не разместить прямо здесь эти картинки! (Заодно взгляну, как сделать так, чтобы картинки занимали не пол-экрана.)
Делюсь не без удовольствия кодом прямо здесь. 💫 (Надеюсь, меня не загрызут люди, которые, не знаю, стояли за созданием bash… кто знает, кто среди читателей будет? Как бы то ни было, это вайб-кодинг — не судите строго. 😝)
Открывайте и используйте на свой страх и риск! 👀
#!/bin/bash
set -euo pipefail
# Определяем, где физически лежит сам скрипт
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="$SCRIPT_DIR/.img_config"
echo "=== ULTIMATE Image Optimization Script (CLI Parallel Edition) ==="
# ==================== ФУНКЦИЯ НАСТРОЙКИ ПУТИ ====================
setup_base_dir() {
echo "--- Настройка базовой директории сайта ---"
echo "Введите абсолютный путь к папке 'img' вашего сайта."
echo "Пример: /home/micu/Documents/My_site/img/"
read -r -p "Путь: " user_path
user_path="${user_path%/}"
if [ ! -d "$user_path" ]; then
echo "⚠️ Ошибка: Директория '$user_path' не существует!"
read -r -p "Всё равно сохранить этот путь? (y/n): " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
exit 1
fi
fi
echo "$user_path" < "$CONFIG_FILE"
echo "✓ Базовый путь успешно сохранен в $CONFIG_FILE"
}
# ==================== ОБРАБОТКА ФЛАГОВ (-c / --change-dir) ====================
if [ "${1:-}" = "-c" ] || [ "${1:-}" = "--change-dir" ]; then
setup_base_dir
echo "Перезапуск скрипта..."
exit 0
fi
if [ ! -f "$CONFIG_FILE" ]; then
echo "Похоже, это первый запуск скрипта!"
setup_base_dir
fi
BASE_OUT_DIR=$(cat "$CONFIG_FILE")
# ==================== ВЫБОР ПОДДИРЕКТОРИИ (Поста/Дня) ====================
echo ""
echo "Текущий базовый путь: $BASE_OUT_DIR"
echo "Введите название целевой подпапки для картинок (например: day_1):"
read -r -p "Подпапка: " sub_dir
sub_dir="${sub_dir#/}"
sub_dir="${sub_dir%/}"
FINAL_DESTINATION="$BASE_OUT_DIR/$sub_dir"
mkdir -p "$FINAL_DESTINATION"
# ==================== ВЫБОР РЕЖИМА СЖАТИЯ ====================
echo ""
echo "Выберите целевой режим сжатия:"
echo "1) Hero / LCP — очень строго (<180 KiB)"
echo "2) Content — строго (<230 KiB)"
echo "3) Banner — умеренно (<350 KiB)"
echo "4) Gallery — максимально (<110 KiB)"
read -r -p "Введите номер (1-4): " mode
case $mode in
1) TARGET_WEBP=184320; MIN_QUALITY=18 ;;
2) TARGET_WEBP=235520; MIN_QUALITY=22 ;;
3) TARGET_WEBP=358400; MIN_QUALITY=28 ;;
4) TARGET_WEBP=112640; MIN_QUALITY=15 ;;
*) echo "По умолчанию Content"; TARGET_WEBP=235520; MIN_QUALITY=22 ;;
esac
SIZES=(640 1200 1920)
shopt -s nullglob
# Экспортируем переменные, чтобы дочерние процессы их видели
export TARGET_WEBP MIN_QUALITY FINAL_DESTINATION sub_dir SCRIPT_DIR
export -a SIZES
# ==================== ФУНКЦИЯ СЖАТИЯ ОДНОГО РАЗМЕРА ====================
compress_size() {
local work="$1" local out_webp="$2" local out_avif="$3"
local target_w="$4" local target_h="$5"
local avif_target=$(( TARGET_WEBP * 70 / 100 ))
local current_w=$target_w local current_h=$target_h
# WebP
magick "$work" -resize "${target_w}x${target_h}" -quality 72 -define webp:method=6 -define webp:pass=10 "$out_webp"
# Агрессивный цикл
for pass in {1..8}; do
[ -f "$out_webp" ] || break
local current_size=$(stat -c %s "$out_webp")
[ "$current_size" -le "$TARGET_WEBP" ] && break
local quality=$(( 72 - pass * 9 ))
[ "$quality" -lt "$MIN_QUALITY" ] && quality=$MIN_QUALITY
current_w=$(( current_w * 90 / 100 ))
current_h=$(( current_h * 90 / 100 ))
if [ $(( current_w < current_h ? current_w : current_h )) -lt 320 ]; then
magick "$work" -resize "${target_w}x${target_h}" -quality "$quality" -define webp:method=6 -define webp:pass=10 -define webp:alpha-quality=30 "$out_webp"
break
fi
magick "$work" -resize "${current_w}x${current_h}" -quality "$quality" -define webp:method=6 -define webp:pass=10 -define webp:alpha-quality=30 "$out_webp"
done
# AVIF
local final_w=$(magick identify -format "%w" "$out_webp" 2</dev/null || echo "$target_w")
local final_h=$(magick identify -format "%h" "$out_webp" 2</dev/null || echo "$target_h")
magick "$work" -strip -units PixelsPerInch -density 72 -resize "${final_w}x${final_h}" -quality 60 "$out_avif"
if [ $(stat -c %s "$out_avif" 2</dev/null || echo 0) -gt "$avif_target" ]; then
magick "$work" -strip -units PixelsPerInch -density 72 -resize "${final_w}x${final_h}" -quality 40 "$out_avif"
fi
}
export -f compress_size
# ==================== ВОРКЕР: ОБРАБОТКА ОДНОГО ФАЙЛА ====================
process_single_image() {
local input="$1"
[ -e "$input" ] || return 0
local name=$(basename "$input")
local base="${name%.*}"
local ext="${name##*.}"
local clean_ext=$(echo "$ext" | tr '[:upper:]' '[:lower:]')
[ "$clean_ext" == "jpeg" ] && clean_ext="jpg"
local img_dir="$FINAL_DESTINATION/$base"
local img_originals_dir="$img_dir/original"
mkdir -p "$img_originals_dir"
# Создаем ИЗОЛИРОВАННУЮ временную папку для конкретно этого файла
local tmp_work_dir=$(mktemp -d "$SCRIPT_DIR/.tmp_work_${base}_XXXXXX")
local work="$tmp_work_dir/${base}_work.${ext}"
# Перенаправляем вывод всего процесса в переменную, чтобы логи не перемешивались в кашу
local log_output=""
log_output+="\n=== Processing: $name ===\n"
log_output+=" → Результаты полетели в: $img_dir\n"
cp "$input" "$img_originals_dir/$name"
cp "$input" "$work"
local has_alpha=0
if [[ "$clean_ext" == "png" ]]; then
if magick identify -format "%[channels]" "$work" 2</dev/null | grep -q 'a'; then
has_alpha=1
fi
fi
if [ "$has_alpha" -eq 1 ]; then
log_output+=" → Alpha PNG — предварительное сжатие...\n"
pngquant --quality=40-85 --speed=1 --force --output "${work%.png}_tmp.png" "$work" && mv "${work%.png}_tmp.png" "$work" || true
oxipng -o 6 --strip safe --quiet "$work" || true
fi
local src_w=$(magick identify -format "%w" "$work" 2</dev/null || echo 0)
local src_h=$(magick identify -format "%h" "$work" 2</dev/null || echo 0)
local max_created_w=0
local max_created_h=0
for size in "${SIZES[@]}"; do
if [ "$size" -gt "$src_w" ] && [ "$size" -gt "$src_h" ]; then continue; fi
if [ "$src_w" -ge "$src_h" ]; then
local target_w=$size; local target_h=$(( src_h * size / src_w ))
else
local target_h=$size; local target_w=$(( src_w * size / src_h ))
fi
local out_webp="$img_dir/${base}-${size}.webp"
local out_avif="$img_dir/${base}-${size}.avif"
compress_size "$work" "$out_webp" "$out_avif" "$target_w" "$target_h"
local final_w=$(magick identify -format "%w" "$out_webp" 2</dev/null || echo "$target_w")
local final_h=$(magick identify -format "%h" "$out_webp" 2</dev/null || echo "$target_h")
log_output+=" ✓ [${size}px] Созданы варианты WebP и AVIF [${final_w}x${final_h}]\n"
max_created_w=$final_w
max_created_h=$final_h
done
# Умный расчет размера фолбэка (Дубли удалены!)
local fallback_w=$max_created_w
local fallback_h=$max_created_h
if [ "$max_created_w" -gt 1200 ] || [ "$max_created_h" -gt 1200 ]; then
if [ "$src_w" -ge "$src_h" ]; then
fallback_w=1200
fallback_h=$(( src_h * 1200 / src_w ))
else
fallback_h=1200
fallback_w=$(( src_w * 1200 / src_h ))
fi
fi
local fallback_ext="jpg"
[ "$has_alpha" -eq 1 ] && fallback_ext="png"
local fallback_file="$img_dir/${base}-fallback.${fallback_ext}"
if [ "$fallback_ext" == "png" ]; then
magick "$work" -resize "${fallback_w}x${fallback_h}" "$fallback_file"
log_output+=" ↳ Оптимизируем палитру уменьшенного PNG-фолбэка...\n"
pngquant --quality=40-85 --speed=1 --force --output "${fallback_file%.png}_tmp.png" "$fallback_file" \
&& mv "${fallback_file%.png}_tmp.png" "$fallback_file" || true
oxipng -o 6 --strip safe --quiet "$fallback_file" || true
else
magick "$work" -strip -units PixelsPerInch -density 72 \
-resize "${fallback_w}x${fallback_h}" -quality 65 "$fallback_file"
fi
local fallback_final_size=$(stat -c %s "$fallback_file" 2</dev/null || echo 0)
local pretty_size=$(numfmt --to=iec "$fallback_final_size")
log_output+=" ✓ Создан дефолтный фолбэк: ${base}-fallback.${fallback_ext} [${fallback_w}x${fallback_h}] ($pretty_size)\n"
# Удаляем оригинал из входящей папки и временную рабочую директорию
rm -f "$input"
rm -rf "$tmp_work_dir"
# --- Подготовка списков существующих файлов для умного srcset ---
local valid_avif=()
local valid_webp=()
for size in "${SIZES[@]}"; do
[ -f "$img_dir/${base}-${size}.avif" ] && valid_avif+=("$size")
[ -f "$img_dir/${base}-${size}.webp" ] && valid_webp+=("$size")
done
# Общая строка sizes для обоих тегов source
local sizes_attr="sizes=\"(max-width: 640px) 100vw, (max-width: 1200px) 80vw, 1200px\""
# Генерируем HTML блок в лог
log_output+="\n → HTML для вашего файла:\n"
log_output+=" <picture>\n"
# Блок AVIF
log_output+=" <source type=\"image/avif\" srcset=\"\n"
local len_avif=${#valid_avif[@]}
for ((i=0; i<len_avif; i++)); do
local size=${valid_avif[i]}
if [ $i -eq $((len_avif - 1)) ]; then
# На последней итерации закрываем кавычку, переносим строку и пишем sizes
log_output+=" img/${sub_dir}/${base}/${base}-${size}.avif ${size}w\"\n $sizes_attr>\n"
else
log_output+=" img/${sub_dir}/${base}/${base}-${size}.avif ${size}w,\n"
fi
done
# Блок WebP
log_output+=" <source type=\"image/webp\" srcset=\"\n"
local len_webp=${#valid_webp[@]}
for ((i=0; i<len_webp; i++)); do
local size=${valid_webp[i]}
if [ $i -eq $((len_webp - 1)) ]; then
# На последней итерации закрываем кавычку, переносим строку и пишем sizes
log_output+=" img/${sub_dir}/${base}/${base}-${size}.webp ${size}w\"\n $sizes_attr>\n"
else
log_output+=" img/${sub_dir}/${base}/${base}-${size}.webp ${size}w,\n"
fi
done
# Блок IMG фолбэка
log_output+=" <img src=\"img/${sub_dir}/${base}/${base}-fallback.${fallback_ext}\" width=\"$fallback_w\" height=\"$fallback_h\" alt=\"Опиши картинку здесь\" loading=\"lazy\">\n"
log_output+=" </picture>\n"
# Выплескиваем весь лог картинки атомарно, чтобы строки не перепутались
echo -e "$log_output"
}
export -f process_single_image
# ==================== ДИСПЕТЧЕР ПОТОКОВ ====================
files=("$SCRIPT_DIR"/*.{jpg,jpeg,png,webp,avif,JPG,JPEG,PNG,WEBP,AVIF})
if [ ${#files[@]} -eq 0 ]; then
echo "❌ Ошибка: В папке '$SCRIPT_DIR' не найдено файлов картинок для обработки!"
exit 1
fi
echo "🚀 Запуск параллельной обработки (Лимит: 5 потоков)..."
MAX_JOBS=5
for input in "${files[@]}"; do
[ -e "$input" ] || continue
# Запускаем обработку одной картинки строго в фоновом режиме (&)
process_single_image "$input" &
# Считаем, сколько фоновых задач запущено прямо сейчас
# Каждый раз, когда количество фоновых задач достигает максимума,
# команда 'wait -n' приостанавливает цикл, ожидая завершения ЛЮБОЙ одной задачи.
while [ "$(jobs -r | wc -l)" -ge "$MAX_JOBS" ]; do
wait -n
done
done
# Ждем завершения последних "хвостов" в очереди
wait
echo ""
echo "=== Все картинки обработаны параллельно и разложены по полочкам! ==="
Первые шажки в CSS
Прочитав заголовок, можно подумать, что я разобрался с курсом от FreeCodeCamp по HTML, но не тут-то было! Пока я возился с ИИ со скриптом, Джеминай так и норовил мне надавать разных советов, что и как можно сделать симпатичнее; потом мне самому стало любопытно, как расстояние увеличить между ссылками в хедере, как сделать отступы у абзацев и всё-всё-всё… В итоге я теперь знаю, как отмечаются в селекторах классы, айди и теги в CSS-файле и некоторые свойства типа text-align и font-size. Не смейтесь, все с чего-то начинают! 🤓☝️
Что ж, на сегодня, кажется, всё. Пора публиковаться на гитхабе!
Так, уже этот абзац пишется после первого коммита. Выяснилось, что на Github Pages относительные пути от корня — типа /img/day_1/akihabara000/akihabara000-640.avif не работают! Это происходит потому, что гитхаб начинает рыскать не в корневой директории репозитория https://wokolai.github.io/personal-site, а в корневой директории моего сайта https://wokolai.github.io. Теперь стремительно меняю все абсолютные пути либо на голые относительные img/day_1/akihabara000/akihabara000-640.avif (идеально для сайтов в корневой папке), либо на ../../../../img/day_1/akihabara000/akihabara000-fallback.jpg (для файлов в архивной директории); выглядит последнее несуразно, по-моему, но зато работает и на реальном сервере, и на гитхабе. Также решил проверить сайт на валидаторе, как это рекомендовал делать парень с курса, который я прохожу, и нашёл у себя кучу ошибок, которые также стремительно исправил. Ну и ещё пару 💫 косметических изменений 💫 сделал, в частности убрал скругление на обводке моего диалога с Клодом — она вообще пока не нужна. Теперь, будучи более осознанным и подготовленным, делаю второй коммит!
День 4: таблицы и забота о здоровье
Дата публикации:
Таблицы
Всем привет! Я пережил экзамен по математике и только сейчас возвращаюсь к работе над сайтом и изучению HTML. В последний раз я остановился на таблицах. Не понял некоторые моменты и хочу остановиться на них поподробнее.
Покажу вам, какой ноут удалось взять на Авито за 80000 ₽. :D
ASUS TUF Gaming A15 FA507NV (модифицированный)
Процессор
AMD Ryzen 5 7535HS
Встроенная видеокарта
AMD Radeon 660M
Дискретная видеокарта
NVIDIA GeForce RTX 4060 Laptop GPU (140 Вт)
Оперативная память
DDR5 Kingston FURY Impact [KF556S40IB-16] 16 ГБ x 2
SSD
WD PC SN740 SDDPNQD-512G-1002
ADATA LEGEND 860
Ёмкость аккумулятора
90 Вт*ч
Оставшаяся ёмкость аккумулятора
87 %
Если честно, доволен покупкой, как слон!
Забота о здоровье глаз и рук
Сегодня значительную часть дня я потратил на выстраивание стратегии «безвредного» досуга за ПК. Что я имею в виду? Ни для кого не секрет, что проводить сутки перед монитором не очень полезно. Это влияет и на здоровье глаз, и на здоровье рук, и на здоровье спины. Со спиной мне ещё предстоит разбираться (пока нет возможности реализовать всё это грамотно), но с глазами и руками, особенно дома, справиться можно.
Итак, начнём с глаз. Проведя небольшой ресёрч, выяснил, что корпоративному миру было даровано несколько советов:
Правило 20-20-20
Незамысловатое предложение, данное в девяностые годы прошлого века оптометристом Джеффри Аншелом, гласит, что каждые 20 минут надо 20 секунд фокусировать взгляд на предмете, находящемся на расстоянии 20 футов (~6 метров). Чтобы его соблюдать, я из Flathub скачал Stretchly — утилиту, которая раз в заданные промежуток времени блокирует экран, чтобы человек мог сделать свои дела со глазами. Я настроил его так, чтобы раз в час также был перерыв на 5 минут — это необходимо для полноценной разминки.
Разминка для глаз
Полная разминка для глаз, которую я теперь делаю раз в час работы за ноутом, указана далее. Как раз отточу навык создания таблиц!
Моя разминка для глаз
Упражнение
Затрачиваемое время (в секундах)
Пальминг
Движения вверх-вниз
Движения вправо-влево
Круговые движения по часовой стрелке
Круговые движения против часовой стрелки
Поморгать
Вблизь-вдаль (по 3 секунды)
Закрыть глаза
Делать её немного утомительно, но я исхожу из того, что она поможет замедлить негативную динамику по моей близорукости.
Расположение монитора (в моём контексте экрана ноутбука)
Проведя также небольшой ресёрч, выяснилось, что верхняя ⅓ экрана должна быть на уровне глаз (или даже немного ниже). Немного поэкспериментировав с подставкой, получилось расположить ноутбук так, как надо.
Моргать
Тут, пожалуй, самое сложное… В процессе работы перед экраном надо не забывать моргать. У меня это получается не очень хорошо, ведь я часто фокусируюсь на том, что делаю, а не на моргании. Мне есть куда расти!
Дальше можно поговорить о здоровье рук, и тут будет полезное предоставить некоторую историю. В период с по я любил проводить время в ритм-игре osu!, где нужно было одной рукой наводиться стилусом на кружочки и другой рукой жать две кнопки (всё это под отличную музыку). Как иногда бывает, я делал это очень неаккуратно: сильно прижимал запястья к столу, неправильно держал стилус (да, бывают разные хваты, и я выбрал один из самых неэргономичных). В итоге у меня начали болеть запястья, и я оставил игру. Потом боль почти полностью исчезла и достигла едва заметного плато, которое я не хочу ухудшать. Сейчас у меня есть сплит-клавиатура со встроенным трекболом и на крайние случаи вертикальная мышь. Эти девайсы сами по себе ставят запястья в куда более естественное положение, но, очевидно, чтобы сократить потенциальные разминки, рекомендуется делать разминки. Раз в час я обращаюсь к популярной в осу-сообществе видеоинструкции от Tykato Fitness. Удачи мне; надеюсь, не заброшу эту историю. :')
Дни 1, 2 и 3: первые потуги
В первые три дня изучение шло в формате «вставляю всё, что показывает чувак с гайда, на одну страницу и смотрю, что будет»; на третий день я решил сделать какую-никакую главную страницу, поэтому лучше всего просто взглянуть, как выглядел сайт в списке снапшотов, следующим после секции про обучение по дням.