ASCII Skeleton Loader
Скрипт заменяет обычную скелетную загрузку изображения на анимацию: ASCII contrast 0 → ASCII contrast 100 → исходная картинка. Его можно подключить один раз и автоматически применять ко всем изображениям сайта.
Как это работает
Скрипт находит изображения по CSS-селектору. Для каждой картинки он создаёт ASCII-представление, накладывает его точно поверх реальной области изображения и анимирует контраст от 0 до 100. После этого ASCII плавно исчезает, а исходное изображение проявляется.
ASCII contrast 0 → промежуточные кадры → ASCII contrast 100 → fade → default image.
Быстрое подключение: куда именно вставлять код
window.ASCII_SKELETON_CONFIG, а уже после него — подключение
ascii-skeleton-site-loader.js. Если поменять их местами, скрипт запустится с настройками по умолчанию.
Вариант 1. Обычный HTML-сайт
Откройте HTML-файл страницы и найдите закрывающий тег
</body>. Вставьте оба блока прямо перед ним.
Было:
<body> ...контент страницы... </body>
Должно стать так:
<body>
...контент страницы...
<script>
window.ASCII_SKELETON_CONFIG = {
selector: 'img:not([data-ascii-skip])',
columns: 96,
frames: 24,
asciiDuration: 1400,
fadeDuration: 500,
charset: '@%#*+=-:. ',
invert: false,
textColor: '#111111',
background: '#ffffff',
lazy: true,
rootMargin: '400px',
observeMutations: true
};
</script>
<script src="/assets/ascii-skeleton-site-loader.js"></script>
</body>
</body>?
К этому моменту основной HTML страницы уже разобран браузером, поэтому loader сразу может найти изображения, не блокируя начальную отрисовку страницы.
Куда положить сам JS-файл
Скачайте ascii-skeleton-site-loader.js и положите его в папку со статическими файлами сайта.
Например:
project/
├── index.html
├── assets/
│ └── ascii-skeleton-site-loader.js
└── images/
├── product-1.webp
└── product-2.webp
Тогда путь в HTML будет:
<script src="/assets/ascii-skeleton-site-loader.js"></script>
Если файл лежит рядом с HTML-страницей, используйте:
<script src="./ascii-skeleton-site-loader.js"></script>
Вариант 2. Один общий шаблон для всего сайта
Если у сайта есть общий layout, footer, template или master-page, вставьте два блока туда один раз. Тогда loader автоматически будет работать на всех страницах, которые используют этот шаблон.
<!-- общий footer / layout сайта -->
<script>
window.ASCII_SKELETON_CONFIG = {
selector: 'img:not([data-ascii-skip])',
columns: 96,
frames: 24,
asciiDuration: 1400,
fadeDuration: 500,
lazy: true,
observeMutations: true
};
</script>
<script src="/assets/ascii-skeleton-site-loader.js"></script>
Вариант 3. Подключение прямо с GitHub Pages
Если вы уже выложили проект на GitHub Pages, сам JS-файл можно не копировать в проект сайта.
Тогда внизу страницы перед </body> вставляется:
<script>
window.ASCII_SKELETON_CONFIG = {
selector: 'img:not([data-ascii-skip])',
columns: 96,
frames: 24,
asciiDuration: 1400,
fadeDuration: 500,
lazy: true,
observeMutations: true
};
</script>
<script src="https://sergeybuharev.github.io/ascii-skeleton-loader/ascii-skeleton-site-loader.js"></script>
Как проверить, что всё подключилось
Ctrl+Shift+R / Cmd+Shift+R.ascii-skeleton-site-loader.js.
Применить ко всем изображениям сайта
По умолчанию можно использовать селектор:
selector: 'img:not([data-ascii-skip])'
Тогда скрипт обработает практически все теги <img>,
кроме явно исключённых.
Что именно вставлять в код сайта
У подключения есть две части, и у каждой своя задача.
<script>
window.ASCII_SKELETON_CONFIG = {
selector: '.product-card img',
columns: 96,
frames: 24,
asciiDuration: 1400,
fadeDuration: 500,
lazy: true,
observeMutations: true
};
</script>
Этот кусок ничего сам не запускает. Он только задаёт настройки будущему loader-скрипту. Поэтому он должен стоять выше подключения JS-файла.
<script src="/assets/ascii-skeleton-site-loader.js"></script>
Этот файл читает настройки из первой части, находит подходящие изображения и запускает эффект.
Минимальный рабочий пример целиком
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Магазин</title>
</head>
<body>
<div class="product-card">
<img src="/images/shoes.webp" alt="Shoes">
</div>
<div class="product-card">
<img src="/images/jacket.webp" alt="Jacket">
</div>
<script>
window.ASCII_SKELETON_CONFIG = {
selector: '.product-card img',
columns: 96,
frames: 24,
asciiDuration: 1400,
fadeDuration: 500,
lazy: true,
observeMutations: true
};
</script>
<script src="/assets/ascii-skeleton-site-loader.js"></script>
</body>
</html>
Если у вас уже есть другие script-теги
Ничего удалять не нужно. Просто добавьте ASCII Loader рядом с ними. Главное — чтобы его конфиг шёл раньше самого loader-файла.
<script src="/assets/app.js"></script>
<script>
window.ASCII_SKELETON_CONFIG = {
selector: '.product-card img'
};
</script>
<script src="/assets/ascii-skeleton-site-loader.js"></script>
<script src="/assets/analytics.js"></script>
Если loader должен работать только на одной странице
Вставьте эти два блока только в HTML этой страницы. В остальные страницы сайта ничего добавлять не нужно.
Если loader должен работать на всём сайте
Добавьте эти два блока в общий шаблон, который присутствует на каждой странице: например,
footer, layout, base.html, общий template CMS или основной layout приложения.
Пример для интернет-магазина
Лучше обрабатывать не вообще все изображения, а только фотографии товаров.
Например, если карточки имеют класс product-card:
window.ASCII_SKELETON_CONFIG = {
selector: '.product-card img',
columns: 84,
frames: 20,
asciiDuration: 1000,
fadeDuration: 350,
charset: '@%#*+=-:. ',
textColor: '#111111',
background: '#ffffff',
lazy: true,
rootMargin: '500px',
observeMutations: true
};
С lazy: true картинки начинают обрабатываться незадолго
до того, как пользователь доскроллит до них. Это полезнее для больших каталогов.
Как исключить отдельное изображение
Добавьте атрибут data-ascii-skip:
<img src="/logo.svg" alt="Logo" data-ascii-skip >
При стандартном селекторе логотип будет пропущен.
Настройки
| Параметр | Что делает | Пример |
|---|---|---|
selector |
CSS-селектор изображений, которые нужно обрабатывать. | '.product-card img' |
columns |
Количество ASCII-колонок. Больше = выше детализация и нагрузка. | 96 |
frames |
Число дискретных кадров между contrast 0 и contrast 100. | 24 |
asciiDuration |
Длительность ASCII-фазы в миллисекундах. | 1400 |
fadeDuration |
Длительность перехода из ASCII в исходную картинку. | 500 |
charset |
Набор символов от плотных к светлым. | '@%#*+=-:. ' |
invert |
Инвертирует соответствие яркости символам. | false |
textColor |
Цвет ASCII. | '#111111' |
background |
Фон ASCII-слоя. | '#ffffff' |
lazy |
Использовать IntersectionObserver и не обрабатывать весь каталог сразу. | true |
rootMargin |
Насколько заранее начать обработку перед viewport. | '400px' |
observeMutations |
Следить за новыми изображениями, появляющимися после первого рендера страницы. | true |
Динамические изображения
Если каталог догружается через infinite scroll, AJAX, React/Vue-компоненты или фильтры, оставьте:
observeMutations: true
Скрипт следит за DOM через MutationObserver и автоматически
добавляет новые изображения в очередь.
Ручной повторный scan
Также можно вызвать:
window.AsciiSkeleton.scan();
Или обработать конкретный тег изображения:
const image = document.querySelector('#hero-image');
window.AsciiSkeleton.process(image);
CORS и изображения с другого домена
Самый надёжный вариант — хранить картинки и скрипт на своём домене/CDN с корректными CORS-заголовками.
Если изображение нельзя прочитать, скрипт оставляет оригинальную картинку без ASCII-эффекта, а не ломает страницу.
Production для большого магазина
Текущая универсальная версия строит ASCII после получения пикселей изображения браузером. Для обычного сайта этого достаточно.
Но если нужно, чтобы ASCII-скелет конкретной фотографии был доступен ещё до загрузки оригинального файла, нужен build-time этап:
Для сотен или тысяч товарных фотографий это наиболее правильная архитектура: эффект появляется мгновенно и не требует декодировать каждое изображение заранее на клиенте.
Подключение через GitHub Pages
Если репозиторий называется ascii-skeleton-loader
в аккаунте sergeybuharev, после включения GitHub Pages
файл будет доступен примерно по адресу:
https://sergeybuharev.github.io/ascii-skeleton-loader/ascii-skeleton-site-loader.js
Тогда подключение выглядит так:
<script>
window.ASCII_SKELETON_CONFIG = {
selector: 'img:not([data-ascii-skip])',
columns: 96,
frames: 24,
asciiDuration: 1400,
fadeDuration: 500,
lazy: true,
observeMutations: true
};
</script>
<script src="https://sergeybuharev.github.io/ascii-skeleton-loader/ascii-skeleton-site-loader.js"></script>