CSS 模式#
本文档描述了我们用于组织和编写 JupyterLab CSS 的模式。JupyterLab 使用一组位于 packages
中的 npm 包开发。这些包都有自己的样式,但依赖于主主题包中定义的 CSS 变量。
CSS 清单#
CSS 类名在代码中内联定义。我们过去将它们作为文件级别的全大写
const
,但我们正在放弃这种做法。包的 CSS 文件位于
style
子目录中,并导入到插件的index.css
中。尽可能使用
theme-light-extension
和theme-dark-extension
包中的 JupyterLab 默认 CSS 变量来样式化包。但是,单个包不应 npm 依赖这些包,以支持主题的替换。插件根据以下描述的约定,少量定义额外的公共/私有 CSS 变量。
CSS 变量#
我们在 JupyterLab 中使用原生 CSS 变量。这是为了实现内置和第三方插件的动态主题化。截至 2017 年 12 月,除了 IE 之外,所有流行浏览器的最新稳定版本都支持 CSS 变量。如果 JupyterLab 部署需要支持这些浏览器,可以使用服务器端 CSS 预处理器,例如 Myth 或 cssnext。
CSS 变量命名#
我们使用以下约定来命名 CSS 变量
所有 CSS 变量都以
--jp-
开头。变量名中的单词应小写并用
-
分隔。下一段应指代组件和子组件,例如
--jp-notebook-cell-
。下一段应指代任何状态修饰符,例如
active
、not-active
或focused
:--jp-notebook-cell-focused
。最后一段通常与 CSS 属性相关,例如
color
、font-size
或background
:--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
字段,我们会在package.json
中使用jupyterlab: { "extraStyles": { "fooLibrary": ["path/to/css"] } }
模式来声明它们。对于不应添加到index.css`
的导入,请更新`SKIP_CSS
在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-at-line-beginning
:应用于可以托管补全器并在行开头空白处有选择的编辑器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”