<!-- ===== FONT + COUNTER ===== -->
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap" rel="stylesheet">
<div class="stats-line">
Разработала более
<span class="countup"
data-from="0"
data-to="200"
data-duration="1500"
data-decimals="0"
data-prefix=""
data-suffix=""
data-ease="easeOutCubic">
0
</span>
проектов
</div>
<style>
body, .stats-line, .countup {
font-family: 'Montserrat', sans-serif;
/* ↑ Шрифт текста и цифр (можно заменить на свой, если подключён) */
}
.stats-line {
font-size: 30px;
/* ↑ Размер текста на компьютере (вся фраза вместе с числом) */
line-height: 1.4;
/* ↑ Межстрочный интервал */
text-align: center;
/* ↑ Выравнивание строки:
center – по центру, left – слева, right – справа */
color: #222;
/* ↑ Цвет основного текста (без числа) */
}
.countup {
font-weight: 700;
/* ↑ Жирность цифры: 400 – тоньше, 700 – яркий акцент */
font-variant-numeric: tabular-nums;
/* ↑ Аккуратные ровные цифры без «дрожания» */
display: inline-block;
min-width: 2ch;
/* ↑ Минимальная ширина числа — чтобы текст не прыгал при анимации */
color: #000;
/* ↑ Цвет числа (можно сделать другим, чем основной текст) */
}
/* ===== МОБИЛЬНАЯ НАСТРОЙКА (по желанию) ===== */
@media (max-width:767px){
.stats-line {
font-size: 22px;
/* ↑ Размер текста на телефоне */
}
}
</style>
<script>
(function () {
var FORMATTER = new Intl.NumberFormat('ru-RU');
function easeLinear(t){ return t; }
function easeOutCubic(t){ return 1 - Math.pow(1 - t, 3); }
function getEaser(name){
return (name === 'linear') ? easeLinear : easeOutCubic;
}
/* проверка: элемент попал в область видимости экрана или нет */
function isInViewport(el){
if (!el || !el.getBoundingClientRect) return false;
var r = el.getBoundingClientRect();
var vh = window.innerHeight || document.documentElement.clientHeight;
return r.top < vh && r.bottom > 0;
}
function animateCount(el){
if (el.__counted) return;
el.__counted = true;
var from = parseFloat(el.getAttribute('data-from') || '0');
var to = parseFloat(el.getAttribute('data-to') || '0');
var duration = parseInt(el.getAttribute('data-duration') || '1200', 10);
var decimals = parseInt(el.getAttribute('data-decimals') || '0', 10);
var prefix = el.getAttribute('data-prefix') || '';
var suffix = el.getAttribute('data-suffix') || '';
var easeName = (el.getAttribute('data-ease') || 'easeOutCubic').trim();
var easeFn = getEaser(easeName);
var start = null;
function render(v){
var factor = Math.pow(10, decimals);
var rounded = Math.round(v * factor) / factor;
var parts = rounded.toFixed(decimals).split('.');
var intPart = FORMATTER.format(parseInt(parts[0], 10));
var out = intPart;
if (decimals > 0) out += ',' + parts[1];
el.textContent = prefix + out + suffix;
}
function step(ts){
if (!start) start = ts;
var p = Math.min((ts - start) / duration, 1);
var eased = easeFn(p);
var value = from + (to - from) * eased;
render(value);
if (p < 1) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
/* запускаем анимацию только у тех .countup, которые попали в экран */
function tryStartAll(){
var nodes = document.querySelectorAll('.countup');
for (var i = 0; i < nodes.length; i++){
var el = nodes[i];
if (!el.__counted && isInViewport(el)){
animateCount(el);
}
}
}
function init(){
tryStartAll();
setTimeout(tryStartAll, 100);
setTimeout(tryStartAll, 400);
window.addEventListener('scroll', tryStartAll, { passive: true });
window.addEventListener('resize', tryStartAll, { passive: true });
window.addEventListener('orientationchange', tryStartAll, { passive: true });
window.addEventListener('touchmove', tryStartAll, { passive: true });
}
if (document.readyState === 'loading'){
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
/* этот код является объектом авторского права (ст. 1259 и 1261 ГК РФ).
Плагиат, продажа или безвозмездная передача третьим лицам без письменного
согласия правообладателя запрещена. © Слотина М.А., 2025 */
})();
</script>