Как подключить JavaScript к HTML: полное руководство для начинающих разработчиков

В своей многолетней практике фронтенд-разработки я часто сталкиваюсь с вопросами о правильном подключении JavaScript к HTML. В этом руководстве я расскажу о всех способах интеграции JS-кода в веб-страницы и поделюсь практическими рекомендациями по их использованию.

1. Встроенный JavaScript в HTML

Самый простой способ добавить JavaScript — использовать тег <script> непосредственно в HTML-документе. Однако из личного опыта рекомендую использовать этот метод только для быстрых прототипов или очень маленьких проектов.

<!DOCTYPE html>
<html>
<head>
    <title>Встроенный JavaScript</title>
</head>
<body>
    <script>
        // Ваш JavaScript код
        console.log('Привет, мир!');
        document.addEventListener('DOMContentLoaded', function() {
            // Код, выполняющийся после загрузки DOM
        });
    </script>
</body>
</html>

2. Подключение внешнего JavaScript файла

В реальных проектах рекомендую использовать внешние JS-файлы. Это улучшает организацию кода, кэширование и поддержку проекта.

<!DOCTYPE html>
<html>
<head>
    <title>Внешний JavaScript</title>
    <!-- Подключение в head с атрибутом defer -->
    <script src="app.js" defer></script>
</head>
<body>
    <!-- Контент страницы -->
    
    <!-- Подключение перед закрывающим тегом body -->
    <script src="main.js"></script>
</body>
</html>

Атрибуты async и defer

На основе опыта оптимизации множества проектов, рекомендую обратить особое внимание на атрибуты async и defer. Они критически важны для производительности.

АтрибутОписаниеКогда использовать
asyncАсинхронная загрузка, выполнение при первой возможностиДля независимых скриптов (аналитика, трекеры)
deferЗагрузка параллельно, выполнение после HTMLДля большинства скриптов приложения

3. Модульный JavaScript

Современный подход к организации JavaScript кода — использование модулей. Это мой предпочтительный метод для средних и крупных проектов.

<!-- HTML файл -->
<script type="module" src="main.js"></script>
// main.js
import { initApp } from './app.js';

initApp();

// app.js
export function initApp() {
    console.log('Приложение инициализировано');
}

4. Лучшие практики подключения JavaScript

  • Размещайте скрипты перед закрывающим тегом </body> или используйте defer для улучшения производительности загрузки страницы
  • Используйте async для независимых скриптов, которые не требуют определенного порядка выполнения
  • Применяйте модульный подход для лучшей организации кода в крупных проектах
  • Минифицируйте JavaScript файлы перед деплоем для уменьшения времени загрузки

5. Отладка подключения JavaScript

При возникновении проблем с подключением JavaScript, первым делом проверьте консоль браузера (F12). Вот типичные ошибки и их решения:

ОшибкаРешение
404 Not FoundПроверьте правильность пути к файлу
Uncaught ReferenceErrorУбедитесь в правильном порядке загрузки скриптов
CORS ошибкаПроверьте настройки сервера и заголовки

6. Проверка мобильной совместимости

При разработке не забывайте тестировать работу JavaScript на мобильных устройствах. Особенно важно проверить:

  • Время загрузки скриптов на медленном соединении
  • Корректность работы touch-событий
  • Потребление памяти на слабых устройствах

Пример оптимизации для мобильных устройств

// Проверка типа устройства
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);

// Условная загрузка скриптов
if (isMobile) {
    // Загружаем облегченную версию
    loadMobileScript();
} else {
    // Загружаем полную версию
    loadDesktopScript();
}

Заключение

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

Почему не работает position: sticky и как это исправить

Давайте разберем основные причины неработоспособности этого свойства и способы их устранения.

Основные причины проблем

1. Отсутствие определенной высоты родительского контейнера

Самая распространенная проблема — родительский элемент не имеет явной высоты. Sticky-элемент должен находиться внутри контейнера с определенными размерами.

/* ❌ Не будет работать */
.parent {
  /* Высота не задана */
}

/* ✅ Правильное решение */
.parent {
  height: 100vh; /* или другое конкретное значение */
  /* min-height тоже подойдет */
}

2. Конфликт с overflow

Второй частый случай — конфликт с CSS-свойством overflow у родительских элементов.

/* ❌ Блокирует работу position: sticky */
.ancestor {
  overflow: hidden;
  overflow-y: scroll;
}

/* ✅ Правильное решение */
.ancestor {
  overflow: visible; /* значение по умолчанию */
}

.scroll-container {
  overflow-y: auto;
}

3. Некорректное значение z-index

При работе в сложных макетах sticky-элемент может оказаться под другими элементами из-за некорректного наслоения.

/* ❌ Элемент может оказаться под другими */
.sticky-element {
  position: sticky;
  top: 0;
}

/* ✅ Правильное решение */
.sticky-element {
  position: sticky;
  top: 0;
  z-index: 100; /* Значение зависит от вашей архитектуры */
}

Практическое решение

Вот полный пример рабочей реализации sticky-навигации:

<div class="wrapper">
  <nav class="sticky-nav">
    <ul>
      <li><a href="#section1">Раздел 1</a></li>
      <li><a href="#section2">Раздел 2</a></li>
    </ul>
  </nav>
  <main class="content">
    <!-- Контент -->
  </main>
</div>
.wrapper {
  /* Важно: не задаем overflow: hidden */
  min-height: 100vh;
  position: relative;
}

.sticky-nav {
  position: sticky;
  top: 20px; /* отступ от верха при прилипании */
  z-index: 10;

  /* Дополнительные стили для улучшения UX */
  transition: all 0.3s ease;
  background: white;
  padding: 15px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

/* Оптимизация для мобильных устройств */
@media (max-width: 768px) {
  .sticky-nav {
    top: 0; /* убираем отступ на мобильных */
    padding: 10px;
  }
}

Проверка работоспособности

Для проверки корректной работы sticky-позиционирования используйте следующий чек-лист:

Что проверяемКак проверяемОжидаемый результат
Высота родителяИнспектор браузераДолжна быть больше высоты sticky-элемента
OverflowПроверка всех родителейНе должно быть hidden или scroll
Z-indexТест с перекрывающими элементамиSticky-элемент должен быть поверх
Мобильные устройстваТест в девтулсПлавный скролл без багов

Оптимизация производительности

При использовании position: sticky важно учитывать производительность:

/* ✅ Оптимизированная версия */
.sticky-element {
  position: sticky;
  top: 0;
  /* Включаем аппаратное ускорение */
  transform: translateZ(0);
  /* Выделяем в отдельный слой */
  will-change: transform;
}

Важные замечания по оптимизации:

  1. Используйте will-change только если есть реальные проблемы с производительностью
  2. Не применяйте тяжелые анимации к sticky-элементам
  3. Следите за количеством sticky-элементов на странице

Поддержка браузерами

// Проверка поддержки position: sticky
const isStickySupported = () => {
  const element = document.createElement('div');
  element.style.position = 'sticky';
  return element.style.position === 'sticky';
}

// Использование
if (!isStickySupported()) {
  // Добавляем fallback решение
  implementStickyPolyfill();
}

Итоги

При работе с position: sticky помните:

  1. Проверяйте высоту родительского контейнера
  2. Избегайте конфликтов с overflow
  3. Правильно управляйте z-index
  4. Оптимизируйте производительность
  5. Предусматривайте fallback для старых браузеров

Следуя этим рекомендациям, вы сможете избежать большинства проблем при реализации sticky-позиционирования в своих проектах.

Несколько кнопок отправки создают путаницу

Зашел на reg.ru пообщаться с поддержкой, после общения увидел вот такой блок с оценкой работы оператора.

Несколько кнопок отправки создают путаницу 1

Я на этом экране увидел только одну кнопку отправки. Щелкнул на «Понравился ответ оператора», а потом нажал на синюю кнопку отправки ответа.

Вижу ошибку и не понимаю. Зачем мне писать текст, если я просто хотел оценить работу оператора. А потом понял, что есть вторая кнопка отправки оценки.

Может быть вы её тоже не увидели. она серая, под вариантами оценки.

Проблемы

  • Нельзя выбрать два варианта: быстрый ответ и мне понравился ответ. А хочу и то и другое
  • Разные кнопки для чата и для отправки оценки. Я считаю, что оба действия — акцентные. Поэтому надо делать обе кнопки синие. У этой страницы странно разделены зоны, где я оцениваю оператора, а где пишу сообщения

Решение

  • Делаем чекбоксы для вариантов оценки оператора.
  • Подсвечиваем цвет кнопки и меняем текст внутри.
Несколько кнопок отправки создают путаницу 2

Как закрыть div при клике вне его области: полное руководство с примерами

Проблема

Одна из частых задач при верстке — закрыть div, например, у модальных окон или выпадающих меню, при клике вне их области. Рассмотрим несколько способов реализации этой функциональности на JavaScript.

1. Базовый способ с использованием addEventListener

Самый простой способ реализации — проверка target элемента при клике:

// HTML структура
// <div id="myDiv" class="popup">Содержимое</div>

document.addEventListener('click', function(event) {
    const myDiv = document.getElementById('myDiv');
    
    if (!myDiv.contains(event.target)) {
        myDiv.style.display = 'none';
    }
});

2. Улучшенная версия с проверкой видимости

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

function setupClickOutside(elementId) {
    const element = document.getElementById(elementId);
    
    document.addEventListener('click', function(event) {
        // Проверяем, виден ли элемент
        if (element.style.display !== 'none') {
            // Проверяем, был ли клик вне элемента
            if (!element.contains(event.target)) {
                element.style.display = 'none';
            }
        }
    });
}

// Использование
setupClickOutside('myDiv');

3. Универсальное решение с кнопкой открытия

Часто нужно обрабатывать также кнопку, которая открывает div:

<button id="toggleButton">Открыть</button>
<div id="myDiv" class="popup">
    Содержимое
</div>
class PopupManager {
    constructor(buttonId, popupId) {
        this.button = document.getElementById(buttonId);
        this.popup = document.getElementById(popupId);
        this.isOpen = false;
        
        this.init();
    }
    
    init() {
        // Обработчик кнопки
        this.button.addEventListener('click', (e) => {
            e.stopPropagation();
            this.togglePopup();
        });
        
        // Обработчик клика вне попапа
        document.addEventListener('click', (e) => {
            if (this.isOpen && !this.popup.contains(e.target)) {
                this.closePopup();
            }
        });
        
        // Предотвращаем закрытие при клике внутри попапа
        this.popup.addEventListener('click', (e) => {
            e.stopPropagation();
        });
    }
    
    togglePopup() {
        if (this.isOpen) {
            this.closePopup();
        } else {
            this.openPopup();
        }
    }
    
    openPopup() {
        this.popup.style.display = 'block';
        this.isOpen = true;
    }
    
    closePopup() {
        this.popup.style.display = 'none';
        this.isOpen = false;
    }
}

// Использование
const popup = new PopupManager('toggleButton', 'myDiv');

4. Работа с множественными попапами

Для управления несколькими попапами на странице:

class MultiplePopupsManager {
    constructor() {
        this.popups = new Map();
        this.handleDocumentClick = this.handleDocumentClick.bind(this);
        
        document.addEventListener('click', this.handleDocumentClick);
    }
    
    addPopup(buttonId, popupId) {
        const button = document.getElementById(buttonId);
        const popup = document.getElementById(popupId);
        
        this.popups.set(popupId, {
            button,
            popup,
            isOpen: false
        });
        
        button.addEventListener('click', (e) => {
            e.stopPropagation();
            this.togglePopup(popupId);
        });
        
        popup.addEventListener('click', (e) => {
            e.stopPropagation();
        });
    }
    
    handleDocumentClick(event) {
        this.popups.forEach((data, id) => {
            if (data.isOpen && !data.popup.contains(event.target)) {
                this.closePopup(id);
            }
        });
    }
    
    togglePopup(popupId) {
        const data = this.popups.get(popupId);
        if (data.isOpen) {
            this.closePopup(popupId);
        } else {
            this.openPopup(popupId);
        }
    }
    
    openPopup(popupId) {
        const data = this.popups.get(popupId);
        data.popup.style.display = 'block';
        data.isOpen = true;
    }
    
    closePopup(popupId) {
        const data = this.popups.get(popupId);
        data.popup.style.display = 'none';
        data.isOpen = false;
    }
}

// Использование
const manager = new MultiplePopupsManager();
manager.addPopup('button1', 'popup1');
manager.addPopup('button2', 'popup2');

5. Обработка ESC для закрытия

Добавим возможность закрытия по клавише ESC:

class EnhancedPopupManager {
    constructor(buttonId, popupId) {
        this.button = document.getElementById(buttonId);
        this.popup = document.getElementById(popupId);
        this.isOpen = false;
        
        this.init();
        this.setupKeyboardEvents();
    }
    
    setupKeyboardEvents() {
        document.addEventListener('keydown', (e) => {
            if (e.key === 'Escape' && this.isOpen) {
                this.closePopup();
            }
        });
    }
    
    // ... остальные методы как в предыдущем примере
}

Рекомендации по использованию

  • Всегда проверяйте наличие элементов перед работой с ними
  • Используйте делегирование событий при работе с динамически созданными элементами
  • Не забывайте очищать обработчики событий, когда они больше не нужны
  • Учитывайте вложенные попапы и их поведение
  • Добавляйте анимации через CSS классы, а не напрямую через style

Заключение

При реализации закрытия div по клику вне его области важно учитывать различные сценарии использования и обеспечить хорошую производительность. Используйте классы для организации кода и не забывайте об обработке краевых случаев. Это позволит создать надёжное и удобное решение для ваших пользователей.

Что такое «use strict» в JavaScript: подробное руководство

«use strict» — это директива в JavaScript, которая переводит код в строгий режим выполнения. Введённая в ECMAScript 5, она помогает писать более безопасный код и избегать распространённых ошибок. Давайте разберем всё по порядку.

Как включить строгий режим

Строгий режим можно активировать двумя способами:

1. Для всего файла

// Должно быть в самом начале файла
'use strict';

function example() {
    // Код в строгом режиме
    let x = 10;
}

2. Для отдельной функции

function strictFunction() {
    'use strict';
    // Этот код будет выполняться в строгом режиме
}

function nonStrictFunction() {
    // Этот код будет выполняться в обычном режиме
}

Основные отличия строгого режима

1. Запрет неявного объявления переменных

// В обычном режиме
name = "John"; // Работает

// В строгом режиме
'use strict';
name = "John"; // Ошибка: name is not defined
let name = "John"; // Правильно

2. Ошибка при удалении неудаляемых свойств

'use strict';

delete Object.prototype; // Выбросит ошибку

3. Запрет дублирования параметров функций

// В обычном режиме - работает
function sum(a, a) {
    return a + a;
}

// В строгом режиме - ошибка
'use strict';
function sum(a, a) { // SyntaxError
    return a + a;
}

Преимущества использования «use strict»

  • Предотвращает случайное создание глобальных переменных
  • Выбрасывает ошибки при распространённых ошибках программирования
  • Запрещает использование потенциально опасных конструкций
  • Упрощает написание «безопасного» кода
  • Оптимизирует производительность кода в некоторых случаях

Что запрещает строгий режим

ДействиеОбычный режимСтрогий режим
Использование необъявленных переменныхРазрешеноОшибка
Удаление переменныхИгнорируетсяОшибка
Дублирование параметровРазрешеноОшибка
Восьмеричные литералыРазрешеныОшибка

Важные замечания при использовании «use strict»

  1. Директива должна быть в начале файла или функции
  2. Отменить строгий режим после его включения невозможно
  3. Современные модули JavaScript автоматически используют строгий режим
  4. При объединении файлов нужно быть внимательным с порядком

Практические примеры

// Пример 1: Предотвращение глобальных переменных
'use strict';

function showAge() {
    age = 25; // Ошибка: age is not defined
}

// Пример 2: Защита от случайного this
'use strict';

function showThis() {
    console.log(this); // undefined
}
showThis();

// Пример 3: Запрет удаления переменных
'use strict';

let x = 1;
delete x; // Ошибка

Рекомендации по использованию

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

Заключение

«use strict» — это важный инструмент для написания качественного JavaScript-кода. Он помогает избегать распространённых ошибок и делает код более безопасным и предсказуемым. В современной разработке использование строгого режима считается хорошей практикой, особенно при работе с новыми проектами.

Поменять цвет svg в background-image

  1. Вставьте ссылку на svg-файл
  2. Выберите цвет.
  3. Скопируйте итоговый код

Генератор css для смены цвета

Код для селектора


 
Live Preview

Заботливо напоминаю 💜

Не забудьте поставить width и heigth

Если нужно скачать SVG

Если нужно скачать SVG — воспользуйтесь ботом.
https://t.me/getsvg_bot

Панель полезных ссылок GetCourse

Я использую Геткурс как разработчик: мне нужно заходить на страницу темы, на страницу заказов.

Чтобы сделать скрины до и после, надо бегать по системным страницам.

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

Наконец они срослись во что-то удобное. Теперь тут есть все нужные ссылки и кнопки. И меню можно скрыть на 10 секунд, чтобы не мешало сделать скриншот.

Как выглядит

Панель полезных ссылок GetCourse 3

Установка

  1. Устанавливаете плагин Tampermonkey или Violentmonkey.
  2. Переходите по ссылке https://greasyfork.org/en/scripts/524 513-context-getcourse-widget
  3. Кликаете на Install, вас перекинет на другую страницу, там кликаем на «Установить»
  4. Переходите на страницу с тренингами
  5. В панели расширений, справа вверху, активируете расширение
  6. На странице появляется панель и у каждого урока и тренинга появляется ID

На старт, внимание, ревью!

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

Скорее всего стройности и структурности в начале тут не будет. Но как и этот сайт, Москва не сразу строилась. Так что буду наполнять постепенно этот раздел «Ревью».

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

Первая будет посвящена моему сайту. Хочешь изменить мир — начинай с себя.

Баги сайта dev-postnov.ru

на 22 января 2025

Кучность и водянистость первого блока

На старт, внимание, ревью! 4
  1. В заголовке нет четкого посыла: какую пользу ты мне принесешь? «Дизайнишь, верстаешь, создаешь продукты» — ты о чем, ты для кого? Зачем я тут и зачем смотреть твой сайт?
  2. Куча текста, пользователь не будет читать. У пользователя 3−5 секунд для принятия решения, если он такую колбасу увидит — сбежит.
  3. Рваные ссылки, ссылки должны быть четко сгруппированы, а не разбросаны по всему тексту.

Полотно текста

На старт, внимание, ревью! 5

Скучаня верстка. Условия работы надо подавать иначе:

  • есть цифры, значит их надо выделять
  • нужна группировка информация: вот про оплату, вот про документы, вот про отношения между мной и исполнителем

Аудио-отзывы

На старт, внимание, ревью! 6
  • Имена без фото — потеря ощущения личности, реального человека. Надо добавлять фото, чтобы можно было соотносить имя, отзыв.
  • Кнопку «Аудио-отзыв» надо переименовать в «Воспроизвести» или «Плей»

Цвет ссылок

На старт, внимание, ревью! 7

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

Добавление тега в заявку в Tilda в зависимости от кнопки или url

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

Как выглядит заявка

Добавление тега в заявку в Tilda в зависимости от кнопки или url 8

Код, вставлять в футер

<script>
    $(document).ready(function() {
    // Объект с настройками для разных услуг
    var serviceSettings = {
        "Готовое оформление": {
            classes: ['.js-services-full-template'],
            urls: ['/full-template-design']
        },
        "Лендинг": {
            classes: ['.js-services-landing'],
            // urls: ['/design', '/services/design']
        },

        "Демо": {
            classes: ['.js-design-demo'],
            // urls: ['/design', '/services/design']
        },
        "Тестовый период": {
            classes: ['.js-test-period'],
            // urls: ['/design', '/services/design']
        }      
    };

    // ДАЛЬШЕ НЕ ТРОГАТЬ!

    // Функция для установки значения скрытого поля
    function setServiceValue(serviceName) {
        $('input[name="service"]').val(serviceName);
    }

    // Обработка кликов по кнопкам
    $.each(serviceSettings, function(serviceName, settings) {
        if (settings.classes) {
            $(settings.classes.join(', ')).click(function(e) {
                e.preventDefault();
                setServiceValue(serviceName);
            });
        }
    });

    // Проверка URL при загрузке страницы
    var currentUrl = window.location.pathname;
    $.each(serviceSettings, function(serviceName, settings) {
        if (settings.urls) {
            $.each(settings.urls, function(index, url) {
                if (currentUrl.indexOf(url) !== -1) {
                    setServiceValue(serviceName);
                    return false; // Прерываем цикл, если URL найден
                }
            });
        }
    });
});
</script>

Обьяснение, как работать с ним

Настройте параметры

В эту часть вставьте name вашего скрытого поля

Добавление тега в заявку в Tilda в зависимости от кнопки или url 9