Skip to content

Commit

Permalink
Use Sass-style comments in Furo (#428)
Browse files Browse the repository at this point in the history
CSS didn't let us use `//` style comments, but SCSS (Sassy CSS) does.
These comments are simpler to write and read.

## Uses `::before` rather than `:before`

I found out that it's preferred to use `::before` for clarity, e.g.
`footer::before` rather than `footer:before`.

## Moves some related rules closer together

Some code was moved closer to its relevant rules. This is prework for an
upcoming refactor to use Sass nesting.

No changes were made -- it only moves the code.
  • Loading branch information
Eric-Arellano authored Jun 29, 2023
1 parent af13986 commit 3776a32
Show file tree
Hide file tree
Showing 12 changed files with 201 additions and 189 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ _qiskit_furo = "qiskit_sphinx_theme"
"Source Code" = "https://github.com/Qiskit/qiskit_sphinx_theme"

[tool.sphinx-theme-builder]
node-version = "18.16.0"
node-version = "18.16.1"


[tool.pytest.ini_options]
Expand Down
94 changes: 51 additions & 43 deletions src/qiskit_sphinx_theme/assets/styles/_admonitions.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// (e.g. warning boxes). We don't use the Success admonition though.

body {
/* See https://carbondesignsystem.com/guidelines/color/usage and
* https://carbondesignsystem.com/components/notification/style/ for where these colors
* come from. */
// See https://carbondesignsystem.com/guidelines/color/usage and
// https://carbondesignsystem.com/components/notification/style/ for where these colors
// come from.
--qiskit-color-admonition-info--background: #edf5ff;
--qiskit-color-admonition-info--border: #0043ce;
--qiskit-color-admonition-warning--background: #fcf4d6;
Expand All @@ -18,25 +18,35 @@ body {
border: 1px solid var(--qiskit-color-admonition-info--background);
}

/* Admonitions are complex because they use a 3px left border with a different color than the rest
* of the div. If we naively used `border-left`, we'd end up with a weird-looking diagonal, as
* described at
* https://stackoverflow.com/questions/18129718/weird-css-behavior-diagonal-border-why-is-the-border-edge-not-straight.
* So, instead, we use `.admonition:before` to set up the left border.
*
* We don't specify the border colors or the `background` for `.admonition:before` because each
* specific admonition type will set them. We also don't set a border-top because we expect the
* border color to be the same as the top's background. */
p.topic-title::before {
-webkit-mask-image: var(--icon-info);
mask-image: var(--icon-info);
background-color: var(--qiskit-color-admonition-info--border);
}

p.topic-title {
background-color: var(--qiskit-color-admonition-info--background);
}

// Admonitions are complex because they use a 3px left border with a different color than the rest
// of the div. If we naively used `border-left`, we'd end up with a weird-looking diagonal, as
// described at
// https://stackoverflow.com/questions/18129718/weird-css-behavior-diagonal-border-why-is-the-border-edge-not-straight.
// So, instead, we use `.admonition::before` to set up the left border.
//
// We don't specify the border colors or the `background` for `.admonition::before` because each
// specific admonition type will set them. We also don't set a border-top because we expect the
// border color to be the same as the top's background.
.admonition {
border-left: 0; /* Turn off Furo's border. */
border-left: 0; // Turn off Furo's border.
border-right-style: solid;
border-right-width: 1px;
border-bottom-style: solid;
border-bottom-width: 1px;
position: relative;
padding-left: 12px;
}
.admonition:before {
.admonition::before {
content: '';
position: absolute;
top: 0;
Expand All @@ -45,16 +55,16 @@ body {
width: 3px;
}

.admonition.attention > .admonition-title:before,
.admonition.caution > .admonition-title:before,
.admonition.important > .admonition-title:before,
.admonition.warning > .admonition-title:before {
/* Rather than using mask-image like Furo normally does, we set `content` to the SVG. This is
* because Carbon requires that we have a black exclamation mark for accessibility: the
* light yellow background wouldn't be distinct enough compared to the dark yellow icon. Mask
* image doesn't let us set colors, only whether to use the background color of the underlying
* HTML element vs. use the background color of the SVG container. So, having a black exclamation
* mark would require setting the entire .admonition-title background color to black. */
.admonition.attention > .admonition-title::before,
.admonition.caution > .admonition-title::before,
.admonition.important > .admonition-title::before,
.admonition.warning > .admonition-title::before {
// Rather than using mask-image like Furo normally does, we set `content` to the SVG. This is
// because Carbon requires that we have a black exclamation mark for accessibility: the
// light yellow background wouldn't be distinct enough compared to the dark yellow icon. Mask
// image doesn't let us set colors, only whether to use the background color of the underlying
// HTML element vs. use the background color of the SVG container. So, having a black exclamation
// mark would require setting the entire .admonition-title background color to black.
content: var(--icon-warning);
-webkit-mask-image: unset;
mask-image: unset;
Expand All @@ -72,15 +82,15 @@ body {
.admonition.warning {
border-color: var(--qiskit-color-admonition-warning--background);
}
.admonition.attention:before,
.admonition.caution:before,
.admonition.important:before,
.admonition.warning:before {
.admonition.attention::before,
.admonition.caution::before,
.admonition.important::before,
.admonition.warning::before {
background: var(--qiskit-color-admonition-warning--border);
}

.admonition.danger > .admonition-title:before,
.admonition.error > .admonition-title:before {
.admonition.danger > .admonition-title::before,
.admonition.error > .admonition-title::before {
-webkit-mask-image: var(--icon-failure);
mask-image: var(--icon-failure);
background-color: var(--qiskit-color-admonition-error--border);
Expand All @@ -93,25 +103,23 @@ body {
.admonition.error {
border-color: var(--qiskit-color-admonition-error--background);
}
.admonition.danger:before,
.admonition.error:before {
.admonition.danger::before,
.admonition.error::before {
background: var(--qiskit-color-admonition-error--border);
}

.admonition > .admonition-title:before,
.admonition.hint > .admonition-title:before,
.admonition.note > .admonition-title:before,
.admonition.tip > .admonition-title:before,
p.topic-title:before {
.admonition > .admonition-title::before,
.admonition.hint > .admonition-title::before,
.admonition.note > .admonition-title::before,
.admonition.tip > .admonition-title::before {
-webkit-mask-image: var(--icon-info);
mask-image: var(--icon-info);
background-color: var(--qiskit-color-admonition-info--border);
}
.admonition > .admonition-title,
.admonition.hint > .admonition-title,
.admonition.note > .admonition-title,
.admonition.tip > .admonition-title,
p.topic-title {
.admonition.tip > .admonition-title {
background-color: var(--qiskit-color-admonition-info--background);
}
.admonition,
Expand All @@ -120,9 +128,9 @@ p.topic-title {
.admonition.tip {
border-color: var(--qiskit-color-admonition-info--background);
}
.admonition:before,
.admonition.hint:before,
.admonition.note:before,
.admonition.tip:before {
.admonition::before,
.admonition.hint::before,
.admonition.note::before,
.admonition.tip::before {
background: var(--qiskit-color-admonition-info--border);
}
50 changes: 25 additions & 25 deletions src/qiskit_sphinx_theme/assets/styles/_api.scss
Original file line number Diff line number Diff line change
@@ -1,47 +1,47 @@
/* By default, Furo uses an aggressive red color for API docs. We use a more muted black and gray. */
// By default, Furo uses an aggressive red color for API docs. We use a more muted black and gray.
body {
--color-api-name: var(--color-foreground-primary);
--color-api-pre-name: var(--color-foreground-secondary);

}

/* Definition lists are used for sections like "Parameters", "Return type", and "Attributes"
* (properties of a class). */
// Definition lists are used for sections like "Parameters", "Return type", and "Attributes"
// (properties of a class).
dl.py:not(.docutils) dt {
/* This causes the definition-term and its border-top to only take up as much space as the
* content, plus padding and margins. */
// This causes the definition-term and its border-top to only take up as much space as the
// content, plus padding and margins.
display: inline-block;
border-top: 2px solid var(--qiskit-color-purple);
background-color: var(--color-background-secondary);
}

/* Rules that impact the top-level entry for the code object, which e.g. has the `[source]` button. */
// Rules that impact the top-level entry for the code object, which e.g. has the `[source]` button.
section > dl.py:not(.docutils) > dt {
/* We normally want to use inline-block for definition terms so that the purple border we add on
* top does not stretch across the whole screen. But, we make an exception here it will have a
* `[source]` button that floats to the right. The spacing of that is non-trivial and was the
* source of issues in Pytorch, so we stick with Furo's spacing. */
// We normally want to use inline-block for definition terms so that the purple border we add on
// top does not stretch across the whole screen. But, we make an exception here it will have a
// `[source]` button that floats to the right. The spacing of that is non-trivial and was the
// source of issues in Pytorch, so we stick with Furo's spacing.
display: block;
/* Make the border less thick so its clear the top-level page header corresponds to this line. */
// Make the border less thick so its clear the top-level page header corresponds to this line.
border-top-width: 1px;
margin-bottom: 1rem;
}
/* It's possible to have multiple entries for the same code object, e.g. when using typing.overload.
* This cancels out the margin-bottom such that only the bottom-most `dt` will have a margin-bottom
* in effect. */
// It's possible to have multiple entries for the same code object, e.g. when using typing.overload.
// This cancels out the margin-bottom such that only the bottom-most `dt` will have a margin-bottom
// in effect.
section > dl.py:not(.docutils) > dt:not(:first-child) {
margin-top: -1rem;
}

/* Fix some of the definition terms like "Parameters" having no padding and being in all caps.
*
* Some Qiskit projects, like Experiments, use custom API sections. Those don't set the class
* `.field-list` on the `dl`, so we change Furo's selector from `.field-list > dt` to `dl > dt`. But,
* to override Furo's properties we don't like, we also have to use `.field-list > dt` for some
* rules to win the specificity war. */
// Fix some of the definition terms like "Parameters" having no padding and being in all caps.
//
// Some Qiskit projects, like Experiments, use custom API sections. Those don't set the class
// `.field-list` on the `dl`, so we change Furo's selector from `.field-list > dt` to `dl > dt`. But,
// to override Furo's properties we don't like, we also have to use `.field-list > dt` for some
// rules to win the specificity war.
dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl > dt {
font-weight: 700;
/* Copied from Furo's `.sig:not(.sig-inline)` */
// Copied from Furo's `.sig:not(.sig-inline)`
padding: .25rem .5rem .25rem 3em;
text-indent: -2.5em;
}
Expand All @@ -55,14 +55,14 @@ dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.
border-radius: 0;
}

/* Revert Furo's special-casing of rubrics for API docs. These rubrics are used for top-level
* section headers like "Attributes" and "Methods". We disagree with the design in
* https://github.com/pradyunsg/furo/discussions/505. Instead, use the rules from `p.rubric`. */
// Revert Furo's special-casing of rubrics for API docs. These rubrics are used for top-level
// section headers like "Attributes" and "Methods". We disagree with the design in
// https://github.com/pradyunsg/furo/discussions/505. Instead, use the rules from `p.rubric`.
dl.py dd p.rubric {
font-size: 1.125em;
font-weight: 700;
line-height: 1.25;
text-transform: unset;
/* This is custom because Furo doesn't have enough space by default. */
// This is custom because Furo doesn't have enough space by default.
margin-top: 1.25em;
}
4 changes: 2 additions & 2 deletions src/qiskit_sphinx_theme/assets/styles/_drop-shadows.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// We use a flat design with Carbon, so disable box-shadows and rounded borders.
//
// `:not(#specifity-war)` is to work around specifity wars.

.admonition,
.topic,
Expand All @@ -8,8 +10,6 @@ kbd:not(.compound) {
box-shadow: none;
}

/* We have a specificity war with Sphinx design elements. The `:not(#specifity-war)` selector
* works around that. */
:not(#specifity-war).sd-card,
:not(#specifity-war).sd-tab-content,
:not(#specifity-war).sd-shadow-sm,
Expand Down
14 changes: 7 additions & 7 deletions src/qiskit_sphinx_theme/assets/styles/_icons.scss
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/* We must use Carbon for all icons: https://carbondesignsystem.com/guidelines/icons/library/.
* To use an icon, download it and format it to one line.
*
* We only override icons for what we use. Others get turned off by e.g. our "admonitions"
* CSS rules. */
// We must use Carbon for all icons: https://carbondesignsystem.com/guidelines/icons/library/.
// To use an icon, download it and format it to one line.
//
// We only override icons for what we use. Others get turned off by e.g. our "admonitions"
// CSS rules.

body {
--icon-search: url('data:image/svg+xml;charset=utf-8,<svg id="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><defs><style>.cls-1 {fill: none;}</style></defs><path d="M29,27.5859l-7.5521-7.5521a11.0177,11.0177,0,1,0-1.4141,1.4141L27.5859,29ZM4,13a9,9,0,1,1,9,9A9.01,9.01,0,0,1,4,13Z" transform="translate(0 0)"/><rect id="_Transparent_Rectangle_" data-name="&lt;Transparent Rectangle&gt;" class="cls-1" width="32" height="32"/></svg>');
--icon-info: url('data:image/svg+xml;charset=utf-8,<svg id="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><defs><style>.cls-1 {fill: none;}</style></defs><path id="inner-path" class="cls-1" d="M16,8a1.5,1.5,0,1,1-1.5,1.5A1.5,1.5,0,0,1,16,8Zm4,13.875H17.125v-8H13v2.25h1.875v5.75H12v2.25h8Z" transform="translate(0 0)"/><path d="M16,2A14,14,0,1,0,30,16,14,14,0,0,0,16,2Zm0,6a1.5,1.5,0,1,1-1.5,1.5A1.5,1.5,0,0,1,16,8Zm4,16.125H12v-2.25h2.875v-5.75H13v-2.25h4.125v8H20Z" transform="translate(0 0)"/><rect id="_Transparent_Rectangle_" data-name="&lt;Transparent Rectangle&gt;" class="cls-1" width="32" height="32"/></svg>');
/* We manually set the CSS classes `st1` and `st2` to the colors for warnings. See the
* admonitions section for an explanation of why. */
// We manually set the CSS classes `st1` and `st2` to the colors for warnings. See
// _admonitions.scss for an explanation of why.
--icon-warning: url('data:image/svg+xml;charset=utf-8,<svg version="1.1" id="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 32 32" style="enable-background:new 0 0 32 32;" xml:space="preserve"><style type="text/css">.st0{fill:none;}.st1{fill:%23f1c21b;}.st2{fill:black;}</style><rect id="Transparent_Rectangle" class="st0" width="32" height="32"/><path id="Compound_Path" class="st1" d="M16,2C8.3,2,2,8.3,2,16s6.3,14,14,14s14-6.3,14-14C30,8.3,23.7,2,16,2z M14.9,8h2.2v11h-2.2V8z M16,25c-0.8,0-1.5-0.7-1.5-1.5S15.2,22,16,22c0.8,0,1.5,0.7,1.5,1.5S16.8,25,16,25z"/><path id="inner-path" class="st2" d="M17.5,23.5c0,0.8-0.7,1.5-1.5,1.5c-0.8,0-1.5-0.7-1.5-1.5S15.2,22,16,22C16.8,22,17.5,22.7,17.5,23.5z M17.1,8h-2.2v11h2.2V8z"/></svg>');
--icon-failure: url('data:image/svg+xml;charset=utf-8,<svg id="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><defs><style>.cls-1 {fill: none;}</style></defs><rect id="inner-path" class="cls-1" x="14.9004" y="7.2004" width="2.1996" height="17.5994" transform="translate(-6.6275 16.0001) rotate(-45)"/><path d="M16,2A13.914,13.914,0,0,0,2,16,13.914,13.914,0,0,0,16,30,13.914,13.914,0,0,0,30,16,13.914,13.914,0,0,0,16,2Zm5.4449,21L9,10.5557,10.5557,9,23,21.4448Z"/><rect id="_Transparent_Rectangle_" data-name="&lt;Transparent Rectangle&gt;" class="cls-1" width="32" height="32"/></svg>');
}
42 changes: 23 additions & 19 deletions src/qiskit_sphinx_theme/assets/styles/_layout.scss
Original file line number Diff line number Diff line change
@@ -1,44 +1,48 @@
// By default, Furo expands the left and right sidebars when the page width increases, but it
// doesn't increase the entry size. It also keeps the page contents fixed at 46em.
//
// Instead, we always keep the side bars the same size, and we expand the main page
// contents. This is a better use of screen real estate and is more consistent with qiskit.org.
//
// But, we only expand the main contents up to 60em because best practices recommend not having
// prose-heavy sites spread content over too long:
// https://www.mediawiki.org/wiki/Reading/Web/Desktop_Improvements/Features/Limiting_content_width#Goals_and_Motivation
// When the max-width is reached, the right page table of contents will stay in its same position and
// whitespace will be added to the right. That is much simpler for us to implement and avoids the
// sidebar from being split way too far from the page content itself.
//
// The easiest way to achieve this is using flexbox, given that Furo already uses it. We keep
// Furo's default values for `width` and `min-width` for the .sidebar-drawer because it's necessary
// for spacing to work properly.

body {
/* This defaults to 15em in Furo, but we want a little bigger. */
// This defaults to 15em in Furo, but we want a little bigger.
--qiskit-left-sidebar-width: 18em;
}

/* Disable Furo making the whole site larger on big screens. This results in `rem` having a
* bigger size, so things like the Qiskit top nav bar getting bigger, which we don't like. */
// Disable Furo making the whole site larger on big screens. This results in `rem` having a
// bigger size, so things like the Qiskit top nav bar getting bigger, which we don't like.
@media (min-width: 97em) {
html {
font-size: 100%;
}
}

/* By default, Furo expands the left and right sidebars when the page width increases, but it
* doesn't increase the entry size. It also keeps the page contents fixed at 46em.
*
* Instead, we always keep the side bars the same size, and we expand the main page
* contents. This is a better use of screen real estate and is more consistent with qiskit.org.
*
* But, we only expand the main contents up to 60em because best practices recommend not having
* prose-heavy sites spread content over too long:
* https://www.mediawiki.org/wiki/Reading/Web/Desktop_Improvements/Features/Limiting_content_width#Goals_and_Motivation
* When the max-width is reached, the right page table of contents will stay in its same position and
* whitespace will be added to the right. That is much simpler for us to implement and avoids the
* sidebar from being split way too far from the page content itself.
*
* The easiest way to achieve this is using flexbox, given that Furo already uses it. We keep
* Furo's default values for `width` and `min-width` because it's necessary for spacing to work
* properly. */
.sidebar-drawer {
flex: 0 0 var(--qiskit-left-sidebar-width);
width: var(--qiskit-left-sidebar-width);
min-width: var(--qiskit-left-sidebar-width);
}

.sidebar-container {
width: var(--qiskit-left-sidebar-width);
}

.content {
flex: 1 1 46em;
max-width: 60em;
}

.toc-drawer {
flex: 0 0 15em;
}
Expand Down
Loading

0 comments on commit 3776a32

Please sign in to comment.