Переназначить класс в css

Переназначить класс в css

Ali Churcher · 27 Jun 2018

I’m a fan of CSS Modules. This clever build step allows you to write CSS in a clean, manageable way. No longer do you have gigantic CSS files. No longer are you scared to delete CSS rules, for fear of unexpected style changes in murky corners of your application. No longer do you have to implement complex CSS naming schemes that are slowly forgotten or implemented inconsistently.

We get these benefits when we use CSS Modules because we write small and simple CSS files. Each of these files (modules) has its own scope, allowing you to reuse simple class names like button in several different modules. Build tools such as css-loader for Webpack then take care of scoping and naming issues during compilation. These scoped class names let you forget about complex selectors, and for the most part specificity.

After some joyful months of using CSS Modules a seemingly simple problem stumped me, and I found myself longing for my old friend specificity. I set out to find out if my longing was a code smell, a limitation of CSS Modules, or something else.

Читайте также:  Если директория существует php

The seemingly simple problem

In our application we have a reusable menu component that is used on every page. In reality it contains some very long German words, but let’s pretend for now that it looks like this:

menu with separators between items

This menu component has an outer div, containing three menu items, each with the class item .

// Menu.jsx import  item, menu > from '..Menu.css' . const Menu = () => ( div className=menu>> button className=item>>HOMEbutton> button className=item>>STOREbutton> button className=item>>CONTACTbutton> div> ) export default Menu 

To create the pipe separator between the items we are using the pseudo element ::after .

/* Menu.css */ .item::after  content: '|'; > 

The special case

menu with no separators between items

As with all applications, we have a special case. When the menu is inside a Header we want to remove the separator lines:

To achieve this we can create a CSS rule in Header.css that will remove the separator and replace it with empty content:

/* Header.css replaces the separator with nothing */ .item::after  content: ' '; > 

When the menu is inside a Header we need this new rule to be used. It must override our existing rule from Menu.css.

This sounds like a job for specificity.

The attempt at overriding a CSS rule

Let’s try it. The principles of specificity tell me that if I want my content declaration to be implemented by the browser then its selector (i.e. .item::after ) must have the highest specificity. If I simply make a new rule that is more specific of course it will be used …right?

/* Menu.css */ .item::after  /* existing rule */ content: '|'; > 
/* Header.css */ .menu .item::after  /* new rule with more specific selector */ content: ' '; > 

With two classes, the selector .menu .item::after defined in the Header.css is much more specific than the .item::after we have defined in Menu.css. But does it work?

menu with separators between items

We still have separators. Our more specific CSS is not being used. Don’t be sad though, this is exactly how things should behave when we use CSS Modules! All the glory of CSS Modules comes from the amazing ability to scope CSS classes uniquely. The reason you are allowed to reuse button classes in several components is because these classes, once compiled, are given scoped names with a unique hash. If we use our developer tools to look at the menu, we can see this happening to the menu’s item class:

compiled menu scoped classes

The menu item elements do not have the class item . Instead, they have been given the compiled class name Menu__item—3FNtb . Likewise the CSS itself is also compiled with a new name.

.Menu__item--3FNtb::after  content: '|'; > .Header__item--1NKCj::after  content: ' '; > 

So while our CSS rule may have won the specificity battle, no element had this class name! For our rule to be picked up, we would need its compiled name .Header__item—1NKCj to be present in the HTML menu item elements.

Stepping back for a second

Getting compiled class names from two different CSS modules into an HTML element sounds complicated. Maybe there are simpler solutions to override our separator style.

Wrap the element?

If we are struggling to target a class inside our menu, could we simply wrap the menu in another element, and apply extra styles to that? This approach works well for things like positioning the menu, but for trying to target an ::after selector on a nested element this solution will fail.

Two components?

You can argue that if we want two different types of menus, then we should have two different components. Sometimes components that look similar actually represent different concepts and should indeed be separated. In this case however, the menus represent the same concept, and I wanted them to be the same component.

Smart menu component?

What if the menu component knew where it was being rendered? It could then display the separators by default, and hide them if it was rendered from the Header component. While this is easy in the short term it means our component is no longer ‘dumb’, it has to deal with things it should not have to worry about. We want our menu to provide a menu, and then be done with it.

Global CSS?

If all else fails we could add our rule to the global CSS. However, while useful for site-wide styles, global CSS is not a good solution for contained components like our menu. We would start to lose the benefits of scoped CSS.

A solution

So we just eliminated many of the common solutions and alternatives for overriding the CSS of a child component from the parent component. It’s time to reapproach the idea of adding the compiled class from Header.css into each of our menu item elements. We know that for our new Header.css rule to be added to the HTML it needs to be present in Menu.jsx when it is compiled. This is something we can achieve by passing the rule into the menu from the Header.

When the header renders the menu we pass in our new .item rule:

//Header.jsx import Menu from '../Menu.jsx' import  item > from './Header.css' // rule to REMOVE the separators . const Header = () => ( header> Menu classes= item >> /> header> ) export default Header 

The menu component accepts this extra class from the Header component and applies it to each menu item. We are using the classnames library cn to allow us to add multiple classes to the element: the item class from Menu.css, and the item class from Header.css. In fact any component that renders a menu now has this option to provide its own implementation of .item .

//Menu.jsx import  menu item > from './Menu.css' // rule to ADD the separators import cn from 'classnames' . const Menu = ( classes = <> >) => ( div className=menu>> button className=cn(item, classes.item)>>HOMEbutton> button className=cn(item, classes.item)>>STOREbutton> button className=cn(item, classes.item)>>CONTACTbutton> div> ) export default Menu 

Let’s check the developer tools to see if these classes are really added:

compiled menu and header scoped classes

Looks good! Now we have both Menu_item—3FNtb and Header_item—1NKCj on our elements. One class adds a separator, one class takes it away. So which style with the browser choose? Will specificity come back to us and allow our more specific Header.css style to win?

Let’s see if we managed to remove the separators.

menu with no separators between items

The header styles that remove the separator has won. We have successfully used specificity to override a style using CSS Modules. This pattern of an HTML element sharing classes from two different components is defined as the Adopted Child Pattern by Simurai.

What’s next?

Wanting a parent component to override the styles of a child component turns out to be a common issue in the community. Thankfully a new :external keyword has been proposed to ease the pain. I recommend reading the proposal for some interesting discussions on the topic. In the mean time, always go for the simplest solution, and know that your friend specificity is always there for you.

Have you had this problem? How did you solve it? Let us know your thoughts in the comments!

Источник

CSS: Можно ли переопределить один класс другим?

Это позволяет мне создать блок с html, который я могу клонировать с помощью jQuery и слегка редактировать по своему вкусу. Однако один из классов, которые я присвоил тому же самому клонированному элементу, устанавливает:

Это приводит к переопределению свойства отображения шаблона, которое полностью разрушает цель создания класса шаблона.

Конечно, я всегда могу просто добавить класс Category одновременно с удалением класса шаблона через jQuery после клонирования, но он не идеален, потому что все дело в том, что html должен быть легко отредактирован, и изменения могут быть сделаны там вместо кода jQuery.

Мысли? Я думаю, может быть, я могу сказать, что дисплей переопределяет другие свойства или что-то в этом роде?

CSS имеет очень четко определенный приоритет.

Если два селектора имеют одинаковый приоритет (в соответствии с вашими двумя селекторами одного класса), то при равном равном всем, тот, который определен последним в коде CSS, является приоритетом.

Итак, простое решение состоит в том, чтобы переместить CSS-шаблон, чтобы опустить ваш CSS-код.

Если вы не можете сделать это по какой-либо причине, ваш лучший вариант – сделать селектор шаблонов более конкретным. Например, если все элементы шаблона содержатся внутри элемента div, и вы знаете, что всегда будет правдой, вы можете изменить селектор на div .template . Теперь он более конкретный, чем селектор .Category , и поэтому должен иметь приоритет.

Наконец, у вас всегда есть опция !important . Я стараюсь избегать использования его, если это возможно, поскольку он имеет тенденцию вызывать проблемы при чрезмерном использовании, но он существует там, где это необходимо, и на самом деле такие случаи относятся к наилучшему оправданному прецеденту для !important . Я могу думать о.

То, что делает !important ; добавьте это к своему значению.

  • Рекомендуется: порядок определения класса в CSS действительно имеет значение, убедитесь, что класс, который вы действительно хотите, находится за другим.
  • Не рекомендуется: используйте !important в конце предложения, это не рекомендуется, потому что если вам нужно переопределить это после того, как это будет сложнее.

Для быстрого решения вы можете просто сделать свое правило css более конкретным:

скажет, что у вас есть этот код:

   div #content .Category .template .otherdiv body .otherdiv  
inner template div
outer template div
outer other div

inner template div будет отображаться как блок, но внешний не будет.

Более конкретно ваши правила css, более “естественно важные”, они есть. В моем коде div .otherdiv будет отображаться с зеленой backgroupd, потому что body .otherdiv более важна, чем .otherdiv

“Начните с 0, добавьте 1000 для атрибута стиля, добавьте 100 для каждого идентификатора, добавьте 10 для каждого атрибута, класса или псевдокласса, добавьте 1 для каждого имени элемента или псевдоэлемента.”

с помощью !important не рекомендуется вообще и не поддерживается всеми браузерами

Добавить! ВАЖНО в .Category.

Источник

Наследование классов в CSS — class, id, !importent

Разберём, как наследуются значения стилей для классов.

В CSS существует последовательность применения стилей для классов.

Например у нас есть следующая структура:

Стили у elements например будут одни, где присутствует одинаковый белый фон.

1. Применение дополнительного класса для перезаписи стиля определённого блока

Если мы добавим например к последнему блоку дополнительный стиль element-two :

И стиль для класса element-two добавим другой цвет фона, например красный. У такого блока с дополнительным классом перезапишутся стили, поменяется фон блока на красный:

А другие стили, которые не будут изменены и добавлены к дополнительному классу, будут наследоваться от класса element

2. Добавление id для перезаписи стиля дополнительного класса element-two

При добавлении id к блоку в HTML и написании стиля для класса element-two с добавлением #block , те стили которые применялись ранее только для дополнительного стиля element-two перезапишутся за счёт айдишника:

2. Добавление !important к значению перезапишет стиль, делая его важным.

Important — переводится как важный и применив данное дополнение к значению, сделает значение ещё более приоритетным:

Но применение !important не является хорошим тоном в среде веб-разработчиков, означает, что при написании кода, что-то было упущено, где-то был просчёт в иерархии при определении классов.

Данный метод не является ошибкой, просто не так круто выглядит в глазах опытных программистов!)

Источник

Оцените статью