css.rst 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. CSS Patterns
  2. ------------
  3. This document describes the patterns we are using to organize and write
  4. CSS for JupyterLab. JupyterLab is developed using a set of npm packages
  5. that are located in ``packages``. Each of these packages has its own
  6. style, but depend on CSS variables dfined in a main theme package.
  7. CSS checklist
  8. ~~~~~~~~~~~~~
  9. - CSS classnames are defined inline in the code. We used to put them as
  10. all caps file-level ``const``\ s, but we are moving away from that.
  11. - CSS files for packages are located within the ``src/style``
  12. subdirectory and imported into the plugin's ``index.css``.
  13. - The JupyterLab default CSS variables in the ``theme-light-extension``
  14. and ``theme-dark-extension`` packages are used to style packages
  15. where ever possible. Individual packages should not npm-depend on
  16. these packages though, to enable the theme to be swapped out.
  17. - Additional public/private CSS variables are defined by plugins
  18. sparingly and in accordance with the conventions described below.
  19. CSS variables
  20. ~~~~~~~~~~~~~
  21. We are using native CSS variables in JupyterLab. This is to enable
  22. dynamic theming of built-in and third party plugins. As of December
  23. 2017, CSS variables are supported in the latest stable versions of all
  24. popular browsers, except for IE. If a JupyterLab deployment needs to
  25. support these browsers, a server side CSS preprocessor such as Myth or
  26. cssnext may be used.
  27. Naming of CSS variables
  28. ^^^^^^^^^^^^^^^^^^^^^^^
  29. We use the following convention for naming CSS variables:
  30. - Start all CSS variables with ``--jp-``.
  31. - Words in the variable name should be lowercase and separated with
  32. ``-``.
  33. - The next segment should refer to the component and subcomponent, such
  34. as ``--jp-notebook-cell-``.
  35. - The next segment should refer to any state modifiers such as
  36. ``active``, ``not-active`` or ``focused``:
  37. ``--jp-notebook-cell-focused``.
  38. - The final segment will typically be related to a CSS properties, such
  39. as ``color``, ``font-size`` or ``background``:
  40. ``--jp-notebook-cell-focused-background``.
  41. Public/private
  42. ^^^^^^^^^^^^^^
  43. Some CSS variables in JupyterLab are considered part of our public API.
  44. Others are considered private and should not be used by third party
  45. plugins or themes. The difference between public and private variables
  46. is simple:
  47. - All private variables begin with ``--jp-private-``
  48. - All variables without the ``private-`` prefix are public.
  49. - Public variables should be defined under the ``:root``
  50. pseudo-selector. This ensures that public CSS variables can be
  51. inspected under the top-level ``<html>`` tag in the browser's dev
  52. tools.
  53. - Where possible, private variables should be defined and scoped under
  54. an appropriate selector other than ``:root``.
  55. CSS variable usage
  56. ^^^^^^^^^^^^^^^^^^
  57. JupyterLab includes a default set of CSS variables in the file:
  58. ``packages/theme-light-extension/style/variables.css``
  59. To ensure consistent design in JupyterLab, all built-in and third party
  60. extensions should use these variables in their styles if at all
  61. possible. Documentation about those variables can be found in the
  62. ``variables.css`` file itself.
  63. Plugins are free to define additional public and private CSS variables
  64. in their own ``index.css`` file, but should do so sparingly.
  65. Again, we consider the names of the public CSS variables in this package
  66. to be our public API for CSS.
  67. File organization
  68. ~~~~~~~~~~~~~~~~~
  69. We are organizing our CSS files in the following manner:
  70. - Each package in the top-level ``packages`` directory should contain
  71. any CSS files in a ``style`` subdirectory that are needed to style
  72. itself.
  73. - Multiple CSS files may be used and organized as needed, but they
  74. should be imported into a single ``index.css`` at the top-level of
  75. the plugin.
  76. CSS class names
  77. ~~~~~~~~~~~~~~~
  78. We have a fairly formal method for naming our CSS classes.
  79. First, CSS class names are associated with TypeScript classes that
  80. extend ``phosphor.Widget``:
  81. The ``.node`` of each such widget should have a CSS class that matches
  82. the name of the TypeScript class:
  83. .. code:: TypeScript
  84. class MyWidget extends Widget {
  85. constructor() {
  86. super();
  87. this.addClass('jp-MyWidget');
  88. }
  89. }
  90. Second, subclasses should have a CSS class for both the parent and
  91. child:
  92. .. code:: TypeScript
  93. class MyWidgetSubclass extends MyWidget {
  94. constructor() {
  95. super(); // Adds `jp-MyWidget`
  96. this.addClass('jp-MyWidgetSubclass');
  97. }
  98. }
  99. In both of these cases, CSS class names with caps-case are reserved for
  100. situations where there is a named TypeScript ``Widget`` subclass. These
  101. classes are a way of a TypeScript class providing a public API for
  102. styling.
  103. Third, children nodes of a ``Widget`` should have a third segment in the
  104. CSS class name that gives a semantic naming of the component, such as:
  105. - ``jp-MyWidget-toolbar``
  106. - ``jp-MyWidget-button``
  107. - ``jp-MyWidget-contentButton``
  108. In general, the parent ``MyWidget`` should add these classes to the
  109. children. This applies when the children are plain DOM nodes or
  110. ``Widget`` instances/subclasses themselves. Thus, the general naming of
  111. CSS classes is of the form ``jp-WidgetName-semanticChild``. This enables
  112. the styling of these children in a manner that is independent of the
  113. children implementation or CSS classes they have themselves.
  114. Fourth, some CSS classes are used to modify the state of a widget:
  115. - ``jp-mod-active``: applied to elements in the active state
  116. - ``jp-mod-hover``: applied to elements in the hover state
  117. - ``jp-mod-selected``: applied to elements while selected
  118. Fifth, some CSS classes are used to distinguish different types of a
  119. widget:
  120. - ``jp-type-separator``: applied to menu items that are separators
  121. - ``jp-type-directory``: applied to elements in the file browser that
  122. are directories
  123. Edge cases
  124. ~~~~~~~~~~
  125. Over time, we have found that there are some edge cases that these rules
  126. don't fully address. Here, we try to clarify those edge cases.
  127. **When should a parent add a class to children?**
  128. Above, we state that a parent (``MyWidget``), should add CSS classes to
  129. children that indicate the semantic function of the child. Thus, the
  130. ``MyWidget`` subclass of ``Widget`` should add ``jp-MyWidget`` to itself
  131. and ``jp-MyWidget-toolbar`` to a toolbar child.
  132. What if the child itself is a ``Widget`` and already has a proper CSS
  133. class name itself, such as ``jp-Toolbar``? Why not use selectors such as
  134. ``.jp-MyWidget .jp-Toolbar`` or ``.jp-MyWidget > .jp-Toolbar``?
  135. The reason is that these selectors are dependent on the implementation
  136. of the toolbar having the ``jp-Toolbar`` CSS class. When ``MyWidget``
  137. adds the ``jp-MyWidget-toolbar`` class, it can style the child
  138. independent of its implementation. The other reason to add the
  139. ``jp-MyWidget-toolbar`` class is if the DOM stucture is highly
  140. recursive, the usual descendant selectors may not be specific to target
  141. only the desired children.
  142. When in doubt, there is little harm done in parents adding selectors to
  143. children.