Стили, размеры, координаты #
Геометрия и стили элемента нужны, когда UI реагирует на размер окна, рисует оверлеи или фиксирует панель checkout. JavaScript читает вычисленные размеры через getBoundingClientRect, меняет оформление через classList и inline-стили element.style.
classList #
Классы — основной способ переключать состояние без inline-CSS:
const bar = document.querySelector('.checkout-bar')
bar.classList.add('is-visible')
bar.classList.remove('is-hidden')
bar.classList.toggle('is-compact', window.innerWidth < 768)
bar.classList.replace('theme-light', 'theme-dark')
Несколько классов за раз:
document.querySelector('.playlist-panel').classList.add('is-open', 'has-focus')
Состояние виджета «свернут»:
function setWidgetCollapsed(widgetEl, collapsed) {
widgetEl.classList.toggle('widget--collapsed', collapsed)
widgetEl.setAttribute('aria-expanded', String(!collapsed))
}
Inline-стили: element.style #
Inline-стили задают конкретные CSS-свойства в camelCase:
const tooltip = document.querySelector('.chart-tooltip')
tooltip.style.left = '120px'
tooltip.style.top = '48px'
tooltip.style.opacity = '1'
tooltip.style.pointerEvents = 'none'
Чтение заданных inline-значений:
tooltip.style.left // "120px"
Вычисленное значение из таблицы стилей — через getComputedStyle:
const styles = getComputedStyle(tooltip)
styles.backgroundColor
parseFloat(styles.paddingTop)
Для анимаций предпочитайте классы и CSS transitions; inline — для координат, зависящих от указателя или scroll.
getBoundingClientRect #
Возвращает размер и положение элемента относительно viewport:
const playBtn = document.querySelector('.player__play')
const rect = playBtn.getBoundingClientRect()
rect.width // ширина с padding и border
rect.height
rect.top // от верхнего края viewport
rect.left
rect.right
rect.bottom
Позиционировать всплывающую подсказку над кнопкой:
function placeTooltip(anchor, tooltip) {
const { top, left, width } = anchor.getBoundingClientRect()
tooltip.style.position = 'fixed'
tooltip.style.left = `${left + width / 2}px`
tooltip.style.top = `${top - 8}px`
tooltip.style.transform = 'translate(-50%, -100%)'
}
Координаты меняются при прокрутке — для scroll-контейнеров пересчитывайте на scroll или используйте position: fixed с актуальным rect.
offsetWidth, clientWidth, scrollWidth #
| Свойство | Что включает |
|---|---|
offsetWidth / offsetHeight | layout-размер + padding + border |
clientWidth / clientHeight | внутренняя область + padding, без border и scrollbar |
scrollWidth / scrollHeight | полный размер контента, включая скрытое переполнение |
const trackList = document.querySelector('.playlist__tracks')
const hasOverflow = trackList.scrollHeight > trackList.clientHeight
trackList.classList.toggle('playlist__tracks--scrollable', hasOverflow)
Размер окна и matchMedia #
const grid = document.querySelector('.dashboard-grid')
function syncGridMode() {
const compact = window.matchMedia('(max-width: 960px)').matches
grid.classList.toggle('dashboard-grid--compact', compact)
}
syncGridMode()
window.addEventListener('resize', syncGridMode)
ResizeObserver точнее отслеживает конкретный элемент, а не всё окно — полезно для виджета с графиком фиксированной высоты.
Практика: sticky checkout-bar #
const checkoutBar = document.querySelector('.checkout-bar')
const sentinel = document.querySelector('.checkout-sentinel')
const observer = new IntersectionObserver(
([entry]) => {
checkoutBar.classList.toggle('checkout-bar--pinned', !entry.isIntersecting)
},
{ rootMargin: '0px', threshold: 0 }
)
observer.observe(sentinel)
Класс checkout-bar--pinned в CSS фиксирует панель; JS только переключает флаг по видимости sentinel-элемента.
Итог #
classList— переключение состояний и тем; избегайте лишнего inline-CSS.element.style— точечные координаты и динамика; вычисленные значения —getComputedStyle.getBoundingClientRect— размер и положение относительно viewport для оверлеев.client*/scroll*/offset*— переполнение и внутренние размеры контейнеров.