CSS 模式#

本文档描述了我们用于组织和编写 JupyterLab CSS 的模式。JupyterLab 是使用位于 packages 中的一组 npm 包开发的。这些包中的每一个都有自己的样式,但依赖于主主题包中定义的 CSS 变量。

CSS 检查清单#

  • CSS 类名在代码中内联定义。我们过去将它们作为所有大写文件级 const,但我们正在逐渐放弃这种做法。

  • 包的 CSS 文件位于 style 子目录中,并导入到插件的 index.css 中。

  • 尽可能使用 theme-light-extensiontheme-dark-extension 包中的 JupyterLab 默认 CSS 变量来为包设置样式。但是,各个包不应该 npm 依赖于这些包,以使主题能够被替换。

  • 插件会谨慎地定义额外的公共/私有 CSS 变量,并符合以下描述的约定。

CSS 变量#

我们在 JupyterLab 中使用原生 CSS 变量。这样做是为了能够对内置和第三方插件进行动态主题化。截至 2017 年 12 月,所有流行浏览器(除了 IE)的最新稳定版本都支持 CSS 变量。如果 JupyterLab 部署需要支持这些浏览器,可以使用服务器端 CSS 预处理器,例如 Myth 或 cssnext。

CSS 变量的命名#

我们使用以下约定来命名 CSS 变量

  • 所有 CSS 变量都以 --jp- 开头。

  • 变量名中的单词应为小写,并用 - 分隔。

  • 下一段应指代组件和子组件,例如 --jp-notebook-cell-

  • 下一段应指代任何状态修饰符,例如 activenot-activefocused--jp-notebook-cell-focused

  • 最后一段通常与 CSS 属性相关,例如 colorfont-sizebackground--jp-notebook-cell-focused-background

公共/私有#

JupyterLab 中的一些 CSS 变量被认为是我们公共 API 的一部分。其他变量被认为是私有的,不应被第三方插件或主题使用。公共变量和私有变量之间的区别很简单

  • 所有私有变量都以 --jp-private- 开头

  • 所有没有 private- 前缀的变量都是公共的。

  • 公共变量应在 :root 伪选择器下定义。这确保了公共 CSS 变量可以在浏览器开发工具的顶级 <html> 标签下进行检查。

  • 尽可能地,私有变量应在除 :root 之外的适当选择器下定义和作用域。

CSS 变量使用#

JupyterLab 在文件 packages/theme-light-extension/style/variables.css 中包含一组默认的 CSS 变量。

为了确保 JupyterLab 中的设计一致性,所有内置和第三方扩展应尽可能在其样式中使用这些变量。有关这些变量的文档可以在 variables.css 文件本身中找到。

插件可以在其自己的 index.css 文件中自由定义额外的公共和私有 CSS 变量,但应谨慎使用。

同样,我们认为此包中公共 CSS 变量的名称是我们 CSS 的公共 API。

文件组织#

我们正在以以下方式组织我们的 CSS 文件

  • 顶层 packages 目录中的每个包都应在其 style 子目录中包含任何用于对其自身进行样式设置所需的 CSS 文件。

  • 所有本地样式应合并到 style/base.css 文件中。

  • 顶层 index.css 文件由 buildutils 作为 integrity 脚本的一部分进行模板化。它按依赖关系顺序导入 CSS,最后是本地 ./base.css。外部库的 CSS 由其 package.json 中的 style 字段确定。如果需要其他文件或外部库没有 style 字段,我们使用 jupyterlab: { "extraStyles": { "fooLibrary": ["path/to/css"] } } 模式在我们的 package.json 中声明它们。对于不应添加到 index.css`, update ``SKIP_CSS in buildutils/src/ensure-repo.ts 的导入。

CSS 类名#

CSS 类命名约定#

我们有一个相当正式的方法来命名我们的 CSS 类。

首先,CSS 类名与扩展 lumino.Widget 的 TypeScript 类相关联

每个此类小部件的 .node 应具有与 TypeScript 类名称匹配的 CSS 类

class MyWidget extends Widget {

  constructor() {
    super();
    this.addClass('jp-MyWidget');
  }

}

其次,子类应同时具有父类和子类的 CSS 类

class MyWidgetSubclass extends MyWidget {

  constructor() {
    super(); // Adds `jp-MyWidget`
    this.addClass('jp-MyWidgetSubclass');
  }

}

在这两种情况下,使用大写字母的 CSS 类名保留用于存在命名 TypeScript Widget 子类的情况。这些类是 TypeScript 类提供样式公共 API 的一种方式。

第三,Widget 的子节点应在 CSS 类名中具有第三个部分,该部分对组件进行语义命名,例如

  • jp-MyWidget-toolbar

  • jp-MyWidget-button

  • jp-MyWidget-contentButton

一般来说,父 MyWidget 应将这些类添加到子节点中。这适用于子节点是普通 DOM 节点或 Widget 实例/子类本身的情况。因此,CSS 类的通用命名形式为 jp-WidgetName-semanticChild。这使得能够以独立于子节点实现或它们本身具有的 CSS 类的样式来对这些子节点进行样式设置。

第四,一些 CSS 类用于修改小部件的状态

  • jp-mod-active: 应用于处于活动状态的元素

  • jp-mod-hover: 应用于处于悬停状态的元素

  • jp-mod-selected: 应用于选中的元素

第五,一些 CSS 类用于区分不同类型的部件

  • jp-type-separator: 应用于作为分隔符的菜单项

  • jp-type-directory: 应用于文件浏览器中作为目录的元素

边缘情况#

随着时间的推移,我们发现这些规则无法完全解决一些边缘情况。在这里,我们尝试澄清这些边缘情况。

何时父级应向子级添加类?

上面我们指出,父级(MyWidget)应向子级添加 CSS 类,以指示子级的语义功能。因此,Widget 的子类 MyWidget 应向自身添加 jp-MyWidget,并向工具栏子级添加 jp-MyWidget-toolbar

如果子级本身是 Widget,并且本身已经具有适当的 CSS 类名,例如 jp-Toolbar?为什么不使用 .jp-MyWidget .jp-Toolbar.jp-MyWidget > .jp-Toolbar 等选择器?

原因是这些选择器依赖于工具栏具有 jp-Toolbar CSS 类的实现。当 MyWidget 添加 jp-MyWidget-toolbar 类时,它可以独立于子级的实现来设置子级的样式。添加 jp-MyWidget-toolbar 类的另一个原因是,如果 DOM 结构高度递归,则通常的后代选择器可能不够具体,无法仅针对所需的子级。

如有疑问,父级向子级添加选择器不会造成太大损害。

常用 CSS 选择器#

我们使用 CSS 选择器来决定显示哪些上下文菜单项,以及在使用键盘快捷键时调用哪个命令。以下常用 CSS 选择器旨在用于添加上下文菜单项和键盘快捷键。

针对部件及其子级的 CSS 类

  • jp-Activity: 应用于主工作区中的元素

  • jp-Cell: 应用于单元格

  • jp-CodeCell: 应用于代码单元格

  • jp-CodeConsole: 应用于控制台

  • jp-CodeConsole-content: 应用于控制台中的内容面板

  • jp-CodeConsole-promptCell: 应用于控制台中活动提示单元格

  • jp-DirListing-content: 应用于文件浏览器目录列表的内容

  • jp-DirListing-item: 应用于文件浏览器目录列表中的项目

  • jp-FileEditor: 应用于文件编辑器

  • jp-ImageViewer: 应用于图像查看器

  • jp-InputArea-editor: 应用于单元格输入区域编辑器

  • jp-Notebook: 应用于笔记本

  • jp-SettingEditor: 应用于设置编辑器

  • jp-SideBar: 应用于侧边栏

  • jp-Terminal: 应用于终端

描述部件状态的 CSS 类

  • jp-mod-current: 应用于当前文档上的元素

  • jp-mod-completer-enabled: 应用于可以托管补全器的编辑器

  • jp-mod-commandMode: 应用于处于命令模式的笔记本

  • jp-mod-editMode: 应用于处于编辑模式的笔记本

  • jp-mod-has-primary-selection: 应用于具有主选区的编辑器

  • jp-mod-in-leading-whitespace: 应用于在行首空白处具有选区的编辑器

  • jp-mod-tooltip: 当页面上存在工具提示时,应用于主体

针对数据属性的 CSS 选择器

  • [data-jp-code-runner]: 应用于可以运行代码的小部件

  • [data-jp-interaction-mode="terminal"]: 当代码控制台处于终端模式时应用

  • [data-jp-interaction-mode="notebook"]: 当代码控制台处于笔记本模式时应用

  • [data-jp-isdir]: 应用于描述文件浏览器项目是否为目录

  • [data-jp-undoer]: 应用于可以撤销的小部件

  • [data-type]: 应用于描述元素类型,例如“document-title”、“submenu”、“inline”