Записки фронтендера
423 subscribers
145 photos
42 videos
1 file
160 links
Все самые свежие обновления в мире Frontend

Бесплатная реклама твоего проекта
https://votby.ru

Общий чат
@fe_notes_chat

Чат помощи с поиском работы
@fe_notes_help

Написать в лс @usersavchenko
Download Telegram
Для тех, кто также как и я каждый раз писал свой обработчик для state-менеджеров, чтобы данные также сохранялись в locale storage и впоследствии не пропадали после перезагрузки страницы: оказывается для этого существуют отдельные библиотеки 😄

Например, для effector это effector-storage, для pinia из vue это pinia-plugin-persistedstate, а для zustand это zustand-persist 💁‍♂️
Недавно попался очередной удобный сайт для подготовки к Frontend собеседованиям. Понравился тем, что в нём собрано всё вместе: теория и практика, алгоритмы и System Design, JavaScript и React.
⚡1
Если вы до сих пор вручную сравниваете npm пакеты, перебирая различные параметры, то самое время обратить внимание на 2 этих сервиса:
1) Bundlephobia
2) NPM Package Info

Они содержат всю необходимую информацию для того, чтобы вы могли точно понять чем одна библиотека лучше другой и принять правильное решение.
⚡1
Если ваш скрипт должен запускаться в разных средах, то, вероятно, вам будет полезен объект globalThis. Он предоставляет доступ к глобальному пространству имен в любом окружении. К примеру, в браузере это window, в Node.js это global, а в веб-воркерах это self. С введением globalThis в ECMAScript 2020 (ES11) уже не нужно писать проверку под каждую отдельную среду, т.к. везде он будет работать правильно:

globalThis === window
globalThis === global
globalThis === self
Я заметил, что мало кто использует в своих проектах рендер-пропсы. Возможно, это связано с тем, что примеров в Интернете не так много, а те из них которые есть - это больше какая-то теория, не сильно применимая на практике. В общем, постарался исправить эту ситуацию, написав новую статью на habr.
В последнее время в сети много шума по поводу DeepSeek - китайского ChatGPT. Попробовал его сам. Пока что на фронтендерские вопросы отвечает неплохо, но значительно слабее конкурента от OpenAI. Будем наблюдать за ним дальше.
Оказывается let и const работают аж на 10% медленнее var 🤦‍♂️😄
Относительно недавно разработчики V8 выпустили отчёт о нововведениях, им получилось сократить эту разницу до 6%.

https://docs.google.com/document/d/1klT7-tQpxtYbwhssRDKfUMEgm-NS3iUeMuApuRgZnAw/edit?tab=t.0
https://v8.dev/blog/holiday-season-2023

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

https://github.com/microsoft/TypeScript/pull/52833
https://github.com/microsoft/TypeScript/pull/52903
🤯2
Ранее при работе с разными наборами стилей возникали проблемы переопределения. Кто-то использовал костыли ввиде !important, кто-то пытался добавить отдельным элементам больше специфичности при помощи дополнительных конструкций в селекторе (например: .container .wrapper .content .form .button.button-danger { ... }) и так далее. Все эти варианты были очень неудобными и чаще всего только усложняли стили для восприятия.

В CSS Cascading and Inheritance Level 5 в 2021 году появился альтернативный вариант для работы с переопределением стилей - директива @layer.

Она позволяет создавать слои с наборами стилей и определять их приоритет самостоятельно.
Например:

@layer reset, base, utilities;

@layer base {
h1 {
color: blue;
}
}

@layer reset {
h1 {
color: red;
}
}

@layer utilities {
h1 {
color: green;
}
}

/*
По итогу применится color: red, т.к. reset по порядку указан первым и благодаря этому имеет наивысший приоритет:

h1 {
color: red;
}

*/


Порядок @layer reset, base, utilities; можно было бы вообще не указывать. Тогда чем бы ниже располагался слой, тем бы больше у него была специфичность. В таком случае color был бы равен green, т.к. utilities располагается ниже остальных.

Вот таким образом можно определять порядок импортируемых стилей:

@import url("reset.css") layer(reset);
@import url("base.css") layer(base);
@import url("utilities.css") layer(utilities);


Этот синтаксис очень удобен при переопределении стилей библиотек:

@import url("tailwind.css") layer(tailwind);

@layer my-styles {
.button {
background: green;
color: white;
}
}
This media is not supported in your browser
VIEW IN TELEGRAM
В CSS с недавнего времени появилось свойство field-sizing. Оно позволяет управлять размерами полей для ввода. А именно: делать так, чтобы размер поля изменялся относительно содержимого (как показано на видео).

Данного эффекта можно достигнуть, указав данное свойство со значением content (по-умолчанию равно fixed).

Ранее нам для подобной реализации пришлось бы создать массивный блок JS кода в 25+ строк.

Поддержка браузерами пока что не сильно большая, но будем надеяться что скоро Firefox и Safari вслед за Chrome подключатся к этой инициативе.

Ссылки:
Официальная документация
В ECMAScript 2025 для Set появились новые методы для работы с множествами. Теперь их стало гораздо проще сравнивать друг с другом и находить различия.

union - объединяет 2 множества и создаёт новый Set с уникальными элементами.
const a = new Set([1, 2, 3]);
const b = new Set([3, 4, 5]);

console.log(a.union(b)); // Set {1, 2, 3, 4, 5}


intersection - создаёт Set с дубликатами из двух множеств.
const a = new Set([1, 2, 3]);
const b = new Set([3, 4, 5]);

console.log(a.intersection(b)); // Set {3}


difference - создаёт Set с элементами, которые присутствуют во множестве a, но отсутствуют во множестве b.
const a = new Set([1, 2, 3]);
const b = new Set([3, 4, 5]);

console.log(a.difference(b)); // Set {1, 2}


symmetricDifference - создаёт Set из уникальных элементов, которые содержатся в двух множествах, но без дубликатов.
const a = new Set([1, 2, 3]);
const b = new Set([3, 4, 5]);

console.log(a.symmetricDifference(b)); // Set {1, 2, 4, 5}


isSubsetOf - проверяет, содержатся ли все элементы множества a во множестве b и возвращает boolean.
const a = new Set([1, 2]);
const b = new Set([1, 2, 3]);

console.log(a.isSubsetOf(b)); // true


isSupersetOf - проверяет, содержатся ли все элементы множества b во множестве a и возвращает boolean.
const a = new Set([1, 2]);
const b = new Set([1, 2, 3]);

console.log(b.isSupersetOf(a)); // true


isDisjointFrom - проверяет, есть ли общие элементы у множеств. Возвращает true, если их нет.
const a = new Set([1, 2, 3]);
const b = new Set([3, 4, 5]);

console.log(a.isDisjointFrom(b)); // false
Не так давно в CSS появились переменные, но мало кто знает, что их ещё можно и типизировать!
Это стало возможным благодаря директиве @property:

@property --my-color {
syntax: '<color>';
inherits: false;
initial-value: red;
}


Или вот такому объявлению JS:
window.CSS.registerProperty({
name: "--my-color",
syntax: "<color>",
inherits: false,
initialValue: "red",
});


1) При помощи свойства syntax мы указываем какой тип будет присвоен нашей переменной (полный список возможных значений и их комбинаций можно найти в спецификации).
2) inherits указывает, будет ли объявленная позже в коде переменная наследоваться потомками или нет.
3) initialValue задаёт значение по-умолчанию по аналогии со вторым параметром внутри var(--btn-bg, red);

Далее мы можем это использовать таким образом:
@property --my-color {
syntax: '<color>';
inherits: false;
initial-value: red;
}

.box {
--my-color: blue;
background-color: var(--my-color); /* Будет использован blue */
}

.box:hover {
--my-color: green; /* Будет использован green */
}

/* Дочерние элементы уже не получат эту переменную, т.к. мы ранее указали inherits: false */

.child {
background-color: var(--my-color); /* Будет использован red, значение по-умолчанию */
}


Если мы назначим переменную, значение которой будет отличаться от типа, указанного @property, то будет взято значение по-умолчанию:
.box {
--my-color: 42px; /* Тип не соответствует <color> */
background-color: var(--my-color); /* Будет использован red, значение по-умолчанию */
}
Большинство разработчиков скорее всего знает о существовании глобальных значений для CSS свойств, таких как inherit, initial и unset, но существуют и другие. Этот список со временем понемногу разрастается.

Расскажу обо всех:

inherit - указывает, что значение должны быть унаследовано от родительского элемента

initial - сбрасывает значение до того, которое установлено по-умолчанию. Например, для display это будет inline даже если элемент до этого был блочным.

unset - если свойство является наследуемым, то будет вести себя как inherit, если нет, то как initial.

revert - возвращает свойство к значению, которое было бы, если бы никаких стилей не было бы применено вообще. То есть для блочного элемента сбросит display до block, а для строчного до inline.

revert-layer - откатывает значение до того, которое было определено в предыдущем каскадном @layer слое.
Наконец-то появилась возможность удобного анимирования появления и исчезновения элементов в CSS, используя дискретные свойства, такие как display. Делается это при помощи свойства transition-behavior со значением allow-discrete и директивы @starting-style.

<!DOCTYPE html>
<html lang="ru">

<head>
<meta charset="UTF-8">
<style>
.box {
width: 200px;
height: 100px;
background: coral;
display: block;
opacity: 1;
transition: opacity 1s, display 1s allow-discrete;
}

.box.hidden {
opacity: 0;
display: none;
}

@starting-style {
.box {
opacity: 0;
}
}
</style>
</head>

<body>
<button onclick="document.querySelector('.box').classList.toggle('hidden');">
Переключить
</button>

<div class="box">Элемент с плавным появлением и исчезновением</div>
</body>

</html>


transition-behavior: allow-discrete - откладывает применение display: none до конца перехода. То есть даёт возможность плавного исчезновения. Поддерживается всеми современными браузерами.

@starting-style - указывает стили, которые должны быть уже применены на момент переключения display с none на block. То есть даёт возможность плавного появления. Пока что не поддерживается только в Firefox.
🔥1