如何在css模块中嵌套类并做出反应?

问题描述 投票:0回答:6

我正在尝试在我的 React 项目中使用 CSS 模块。问题的第一部分是,如果我编写嵌套的 css 类(使用 sass),我不知道是否可以访问内部类,因为这些类似乎也被编译成唯一的类名。一些代码:

<div className={this.state.visible ? styles.header+" menu-visible" : styles.header}>
    <div className="menu">
        <a className="link">title</a>
    </div>
</div>
.header {
    &.menu-visible {
        .menu {
            display: block;
        }
    }
}

我有一个包装类,有时是“菜单可见”的,它会更改所有子级的属性,在 React 中这样做是不是不好的做法?

如果菜单可见,.header 内有多个类会被更改,因此仅更改包装类会很方便,我可以以某种方式引用子级吗?这样仍然嵌套在 scss 中吗?

编辑

我能想到的一个解决方案是将 className="menu" 替换为 className={styles.header.menu} 但这似乎不起作用。问题是,如果 .menu 的父级具有 menu-visible 类,我希望 .menu 更改其属性。

reactjs css-modules
6个回答
95
投票

我解决了。我想我只是在心里做得太过分了。我可以只写

styles.header.menu
,而不是写
styles.menu
,即使它是嵌套的。

示例(React + JSX):

<div className={styles.header}>
  <div className={styles.menu}>
      Whatever
  </div>
</div>

.header {
   .menu {
      display: block;
   }
 }

58
投票

更好地保留嵌套类和样式的替代解决方案是在使用 sass 或 less 等预处理器时,在所有嵌套类上使用全局范围

:global

.header {
  :global {
    .menu {
      display: none;

      &.menu-visible {
        display:block;
      }
    }
  }
}
<div className={styles.header}>
  <div className="menu menu-visible">
      Whatever
  </div>
</div>

:global
作用域运算符告诉CSS模块编译器保留其中定义的所有类名,这样您就不需要将这些嵌套类名也注入到组件中。使用
:global
确实违背了 CSS 模块的初衷,您可能会发现任何单独的子组件样式现在都会受到全局范围类的影响。


23
投票

可以使用[class~=classname]

.header {
   [class~=menu] {
      display: block;
   }
 }

不会被检测为一个类并单独留下。


10
投票

请注意,当深度嵌套选择器时,已接受答案中的解决方案可能会导致 css 包大小显着增加。

已接受的解决方案,还有 1 层嵌套

JSX:

<div className={styles.header}>
  <ul className={styles.menu}>
    <li className={styles.item}>
      Whatever
    </li>
  </ul>
</div>

SCSS:

.header {
   .menu {
      .item {
        display: block;
      }
   }
 }

输出(假设 css 模块的默认设置):

.myComponent_header__27ep6 .myComponent_menu__32Qvy  .myComponent_item__2RWLN {
  display: block
}

替代解决方案

更好的编写方式是松散地借用 BEM 方法并使用父选择器:

JSX:

<div className={styles.header}>
  <ul className={styles.headerMenu}>
    <li className={styles.headerMenuItem}>
      Whatever
    </li>
  </ul>
</div>

SCSS:

.header {
   &Menu {
     &Item {
       display: block;
     }
   }
 }

输出:

.myComponent_headerMenuItem__37djq { display: block }

1
投票

不太确定为什么上面可怕的黑客行为是公认的答案。也许它对某些奇怪环境下的人有用。

  1. 发布的代码不起作用
  2. 这从根本上打破了 CSS 中的“C”! 现在可以成功地争论CSS模块本身打破了CSS的“级联”性质,但同样,它的目标是将级联限制在一定范围内......正如我们从问题及其各种“解决方案”中看到的那样’,这只是部分成功。真是太可惜了,一定要这样!

解决此问题的一种更“CSS 友好”的方法是在子类名称中显式声明类层次结构,如下所示(例如 mymenu.module.css):

.header {
}

.headerMenu {
  display: block;
}

请注意,在这种情况下,您不能使用方括号表示法,因为 CSS 模块看不到它 - 因此类名不能有连字符,并且不能“正常”级联 ́\(ツ) / ́ - 例如:

.header-menu {
  display: block;
}

和/或

.header .menu {
  display: block;
}

不起作用,因为括号选择器符号(又一个 CSS hack!)根本无法识别它。

虽然这仍然是一个[本地] CSS hack,但至少它仅限于手头的类,不会使你的包的大小膨胀,并且也保留你的 CSS,CSS。


0
投票

我不知道这是否有帮助,但我找到了如下方法:

文件:package.json

"dependencies": {
  ...,
  "sass": "^1.49.9"
}

文件:test.scss

.box {
    width: 100%;
}

.boxItem {
    background: red;

    &.first {
        background: blue;
    }

    &.second {
        background: silver;
    }
}

文件 test.js

import React from 'react'
import styles from "./test.scss";

const test = () => {
  return (
    <div className={`${styles.box}`}>
      <div className={`${styles.boxItem} ${styles.first}`}>Test 01</div>
      <div className={`${styles.boxItem} ${styles.second}`}>Test 02</div>
      <div className={`${styles.boxItem}`}>Test 03</div>
    </div>
  );
};

导出默认测试;

© www.soinside.com 2019 - 2024. All rights reserved.