Руководство по определению области видимости CSS-переменных в Angular

0 3

Самое замечательное в CSS-переменных – тот факт, что они могут применяться к псевдоклассам, таким как наведение и фокусировка. Еще одна особенность CSS-переменных, в которую мы пока не углублялись, заключается в том, что они могут применяться как на уровне документа – глобально, – так и локально, для отдельных элементах. В этом уроке мы рассмотрим некоторые плюсы и минусы глобального и локального определения области видимости переменных, а также узнаем, как применять стили к определенным элементам во время выполнения кода.

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

Подобно скомпилированным расширениям CSS, таким как Sass и Less, CSS теперь использует свои собственные «чистые» переменные. Они определяются путем добавления двойного тире (–) перед именем переменной. После этого переменные CSS передаются в в функцию var() для получения доступа к ее значению. CSS-переменные объявляют в верхней части файла CSS, как показано в первом примере ниже, или на уровне правил, как это сделано во втором примере:

1) Объявление переменной на уровне документа

--main-bg-color: brown; .background {   background-color: var(--main-bg-color); }

2) Объявление переменной на уровне правил

.wrapper:focus {   background-color: --focus-color; }

При использовании метода setProperty() CSSStyleDeclaration на уровне документа в TypeScript или JavaScript переменная добавляется во встроенный атрибут стиля HTML тега:

document.documentElement.style.setProperty('--focus-color', this.textcolor);

Руководство по определению области видимости CSS-переменных в Angular

Этот метод во многом похож на объявление пользовательского свойства в псевдоклассе :root в таблице стилей:

:root {   --main-bg-color: brown; }

В этом методе нет ничего плохого, но вам следует помнить, что такой стиль затронет все элементы, которые ссылаются на переменную —main-bg-color. Хорошей практикой в веб-разработке считается объявление переменных в максимально ограниченной области, насколько это возможно. Этот совет подпадает под старое и общепринятое правило, которое гласит, что глобальные переменные – это плохой стиль программирования. Независимо от того, согласны ли вы с этим утверждением или нет, существует немало веских причин для ограничения области действия пользовательских свойств.

Предположим, нам нужно определить атрибут — focus-color для определенного div элемента в TypeScript коде:

@ViewChild("svgImage", { static: true })  private svgImageRef: ElementRef<HTMLDivElement>; //далее в коде svgImageRef.nativeElement.style.setProperty('--focus-color', 'gray');

Как можно увидеть на скриншоте, в результате этого действия CSS-переменная была добавлена в инлайновый стиль элемента:

Руководство по определению области видимости CSS-переменных в Angular

Локальное объявление переменной

Возьмем, к примеру, фрагмент CSS, где объявляются две переменные цвета – одна меняет цвет фона при наведении курсора, вторая определяет оттенок рамки фокуса:

.news-image {   $hoverColor: var(--hover-color);   $focusColor: var(--focus-color);   :hover {     background-color: $hoverColor;   }   &:focus {     outline: 2px solid $focusColor;   } }

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

Напомним, что в примере привязки стилей CSS к событиям в приложениях Angular мы использовали глобальные CSS-переменные для создания трех цветных квадратов предварительного просмотра. Теперь давайте применим ту же технику к компоненту ленты новостей, но с использованием объявлений локальных переменных, как было показано выше.

Для создания ссылки на div, содержащий новость и изображение новостей в TypeScript коде, нам нужно добавить ссылку на шаблон #svgimage в тег div:

<div   class="news-image"   #svgImage   tabindex="0"   style="background-position: center; background-size: cover"   [style.backgroundColor]="backgroundColor" >   <svg>   ...   </svg> </div>

В верхней части класса FeedComponent вы увидите тот же способ объявления переменной @input, что и в предыдущем примере, а также ссылку на div-элемент с новостями и изображениями, любезно предоставленную декоратором ввода @ViewChild:

export class FeedComponent implements AfterContentInit, OnChanges {   @Input('background-color')    backgroundColor: string = 'blue';   @Input('hover-background-color')    hoverBackgroundColor = 'cyan';   @Input('focus-border-color')    focusBorderColor = '#CCCCCC';    @ViewChild('svgImage', { static: true })   private svgImageRef: ElementRef<HTMLDivElement>   //...  } export class FeedComponent implements AfterContentInit, OnChanges {   @Input('background-color')    backgroundColor: string = 'blue';   @Input('hover-background-color')    hoverBackgroundColor = 'cyan';   @Input('focus-border-color')    focusBorderColor = '#CCCCCC';    @ViewChild('svgImage', { static: true })   private svgImageRef: ElementRef<HTMLDivElement>   //...    }

Вероятно, вы заметили, что компонент ленты новостей теперь использует хуки жизненного цикла AfterContentInit и On Changes. Давайте рассмотрим их подробнее.

Инициализация переменной

Хотя вы можете получить доступ к переменной @Input в событии ngOnInit, вы не сможете ссылаться на элементы DOM до хука ngAfterContentInit. Объявление стиля CSSStyleDeclaration для svgImageRefсохраняется в частной переменной-члене класса для последующего использования. После этого для элемента svgImageRef устанавливаются цвета наведения и фокусировки:

private svgStyle: CSSStyleDeclaration;  ngAfterContentInit(): void {   this.svgStyle = this.svgImageRef.nativeElement.style;   this.svgStyle.setProperty(     '--hover-color', this.hoverBackgroundColor);   this.svgStyle.setProperty(     '--focus-color', this.focusBorderColor); }

Обновление значений CSS-переменных

Поскольку хук жизненного цикла ngAfterContentInit устанавливает CSS-переменные при первой загрузке приложения, нам необходимо использовать другой хук для обновления входных переменных, которое происходит каждый раз, когда пользователь вводит данные в поля ввода и нажимает кнопку «Применить». Здесь нам как раз пригодится ngOnChanges: он вызывается, когда изменяется любое свойство директивы, связанное с данными, – другими словами, всякий раз, когда изменяется значение @Input переменной компонента.

В жизненном цикле приложения ngOnChanges в первый раз срабатывает на самом раннем этапе, фактически до ngOnInit(). Поэтому нет смысла обновлять CSS-цвета при первом обходе, так как модель DOM в это время еще не будет готова. Мы можем проверить, является ли обход документа первым с помощью значения свойства firstChange. Это свойство равно true, когда ngOnChanges вызывается впервые. Помимо этого, необходимо проверить саму переменную, так как каждая связанная переменная возвращается вместе с соответствующим экземпляром SimpleChanges. Вот что мы получаем для каждой из наших переменных @Input при первом выполнении ngOnChanges:

Руководство по определению области видимости CSS-переменных в Angular

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

ngOnChanges(changes: SimpleChanges): void {   if (changes.hoverBackgroundColor      &&& !changes.hoverBackgroundColor.firstChange) {     this.svgStyle.setProperty(       '--hover-color', changes.hoverBackgroundColor.currentValue);   }   if (changes.focusBorderColor     &&& !changes.focusBorderColor.firstChange) {     this.svgStyle.setProperty(       '--Focus-color', changes.focusBorderColor.currentValue);   } }

Демонстрацию работы этого кода можно посмотреть на stackblitz.com:

Руководство по определению области видимости CSS-переменных в Angular

Заключение

В этом уроке мы рассмотрели метод определения области видимости CSS-переменных, а также обсудили то, как применять пользовательские свойства к определенным элементам с помощью TypeScript и JavaScript. В конечном итоге, решение о том, объявлять ли ваши CSS-переменные глобально или внутри блоков правил, остается за вами. Я лично стараюсь определять все переменные настолько локально, насколько это возможно, потому что увеличить область определения всегда можно позже.

Источник: www.internet-technologies.ru

Оставьте ответ

Ваш электронный адрес не будет опубликован.