]> git.draconx.ca Git - homepage.git/blobdiff - content/style.scss
Attempt to improve focus ring styles in modern browsers.
[homepage.git] / content / style.scss
index 82b872028fc1db23c80e229cbcc3a0b33f59196f..d53717d9d0f692a02d356d0cb5c27574b981d1a8 100644 (file)
@@ -1,7 +1,7 @@
-/*
+/*!
  * Nick's web site: default stylesheet
  *
- * Copyright © 2018-2020 Nick Bowler
+ * Copyright © 2018-2022 Nick Bowler
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -32,6 +32,8 @@ $annotationcolour:  #708090;
 
 $tableshadecolour:  #f5f5f5;
 
+$focusringcolour: #628cb2;
+
 @mixin header_size($maxwidth, $fontsize) {
     font-size: $fontsize;
     max-width: 1em * ($maxwidth / $fontsize);
@@ -44,15 +46,56 @@ body {
     margin: 1em;
 }
 
-a:link { color: $linkdefaultcolour; }
-a:visited { color: $linkvisitedcolour; }
-a:active { color: $linkactivecolour; }
+a:link { color: $linkdefaultcolour; border-color: $linkdefaultcolour; }
+a:visited { color: $linkvisitedcolour; border-color: $linkvisitedcolour; }
+a:active { color: $linkactivecolour; border-color: $linkactivecolour; }
+
+@supports (outline-style: auto) {
+    a:link { border-width: 0; }
+    a:focus { outline: auto $focusringcolour; }
+    li, td, dt { &>a:link { border: solid 1px transparent; } }
+}
 
 h1 { @include header_size(60em, 2em); }
 h2 { @include header_size(60em, 1.5em); }
 h5 { @include header_size(60em, 1em); }
 
-p>img { max-width: 40em; width: 100%; height: auto; }
+@supports (display: grid) {
+    .gallery {
+        display: grid;
+        grid-column-gap: 1em;
+        grid-template-columns: repeat( auto-fill, minmax(18em, 1fr) );
+        align-items: center;
+
+        p.img { margin: 0.5em 0; }
+    }
+}
+
+p.img {
+    text-align: center;
+
+    img {
+        vertical-align: bottom;
+        max-width: 40em;
+        width: 100%;
+        height: auto;
+    }
+
+    a {
+        text-decoration: none;
+        display: inline-block;
+        border: solid 2px;
+    }
+
+    small {
+        color: $foregroundcolour;
+        text-align: justify;
+        @media (max-width: 24em) { text-align: left; }
+        padding: 0.5ex;
+        display: block;
+        font-size: 0.9em;
+    }
+}
 
 p, dt, dd, li {
     text-align: justify;
@@ -68,6 +111,10 @@ p, table, div, ul, ol, dl, hr {
 }
 
 p, table, body>div, h5 { margin: 1em 0; }
+blockquote {
+    @media (max-width: 28em) { margin: 1em 0.5em; }
+    margin: 1em;
+}
 
 li { margin: 0 0 0 2em; }
 dd { margin: 0 0 0 1em; }
@@ -83,6 +130,14 @@ kbd {
     font-family: monospace;
     font-size: 0.95em;
     &:before { content: "% "; }
+    &>span { white-space: nowrap; }
+
+    blockquote & {
+        display: block;
+        text-align: left;
+        padding-left: 3em;
+        text-indent: -3em;
+    }
 }
 
 .permalink {
@@ -118,6 +173,7 @@ td, th {
 
 thead>tr, tbody>tr { border: solid $ruledefaultcolour; }
 th, thead>tr { border-bottom: 1px solid $rulestrongcolour; }
+tbody+tbody { border-bottom: 1px solid $ruledefaultcolour; }
 *>table, *>th { border: none; }
 thead>tr { border-width: 1px; }
 tbody>tr { border-width: 0 1px; }
@@ -137,6 +193,194 @@ table.cc {
     }
 }
 
+// CSS rules for stortable clicky table headers: Update the display of
+// the /table based on the current state.  Each column has its own set
+// nearly-identical rules, only the class names differ.
+//
+// The clickytables.xsl stylesheet generates two inputs for each column.
+// These inputs are siblings of the table and all precede it in document
+// order.  Moreover, the inputs for a column are ordered with respect to
+// each other, in this sequence:
+//
+//   input.clicky-NAME     -- checked iff NAME is selected for sorting.
+//   input.clicky-NAME-rev -- checked to select reverse order.
+//
+// One of the column selection inputs will have a 'checked' attribute to
+// indicate the default order.  This input is always first in document
+// order.  No other inputs begin checked.
+//
+// The table itself consists of a thead (where the header labels are
+// located) and two tbody elements.  The bulk of these rules relate
+// to updating the headers to visually indicate the current state.
+//
+// A sortable column's th element has the .clicky-NAME class, matching
+// its corresponding inputs, and has two label children.  The first label
+// is visible only when the column is unselected, and is linked to the
+// .clicky-NAME input to activate that column.  The second label is visible
+// only on the selected column and is linked to the .clicky-NAME-rev input
+// to toggle the reverse order.
+//
+// For the table body, the first tbody contains the default ordering
+// and is not styled by these rules (except to hide it when alternate
+// orderings are selected).  The second tbody contains rows for all
+// alternate orderings, and is revealed by these rules.  When revealed,
+// rows with the NAMEfwd or NAMErev class (for the forward and reverse
+// orderings, respectively) are shown and other rows are hidden.
+
+$clickynames: name, date, size;
+@each $col in $clickynames {
+    input.clicky-#{$col} {
+        &:checked {
+            &~table {
+                // Update table header state
+                & th.clicky-#{$col} {
+                    label~label {
+                        display: -moz-inline-box !important;
+                        display: inline-block !important;
+                    }
+                    label { display: none; }
+                }
+
+                // Show only appropriate items from the sort body (forward)
+                &>tbody+tbody>tr.#{$col}fwd { display: table-row; }
+                &>tbody+tbody>tr { display: none; }
+
+                // Unhide sort body
+                &>tbody {
+                    &+tbody { display: table-row-group !important; }
+                    display: none;
+                }
+            }
+
+            // reverse state for selected sort column
+            &~input.clicky-#{$col}-rev {
+                &:checked ~ table {
+                    // Show only appropriate items from sort body (reversed)
+                    &>tbody+tbody>tr.#{$col}rev { display: table-row; }
+                    &>tbody+tbody>tr { display: none; }
+
+                    // Unhide sort body
+                    &>tbody {
+                        &+tbody { display: table-row-group !important; }
+                        display: none;
+                    }
+                }
+
+                // Unhide to allow keyboard navigation to this input
+                display: block !important;
+            }
+        }
+
+        // If default input element is the only one selected, match it to
+        // return to default view (overriding the changes above).  It is
+        // always the first input element among all the sibling elements.
+        // This seems to interoperate better than using the [checked] or
+        // :first-of-type selectors.
+        @at-root &:first-child, :not(input)+& {
+            &:checked~table>tbody {
+                &+tbody { display: none !important; }
+                display: table-row-group;
+            }
+        }
+
+        // Unhide to allow keyboard navigation
+        display: block !important;
+        pointer-events: none;
+        position: absolute;
+        opacity: 0;
+        z-index: -1;
+    }
+
+    input.clicky-#{$col}-rev {
+        &:checked ~ table {
+            // Update table header state
+            & th.clicky-#{$col} {
+                .svg+.svg {
+                    display: -moz-inline-box !important;
+                    display: inline-block !important;
+                }
+                .svg { display: none; }
+            }
+        }
+
+        pointer-events: none;
+        position: absolute;
+        opacity: 0;
+        z-index: -2;
+    }
+
+    $focuslabel: ":focus ~ table th.clicky-#{$col}>label~label";
+    #{"input.clicky-#{$col+$focuslabel}"}>span:first-child
+    , #{"input.clicky-#{$col}-rev#{$focuslabel}"} .svg
+    {
+        border-color: $foregroundcolour;
+        @at-root { @supports (outline-style: auto) { & {
+            border-color: transparent;
+            outline: auto $focusringcolour;
+        }}}
+    }
+}
+
+thead.clicky label {
+    white-space: nowrap;
+    line-height: 1.5em;
+    cursor: pointer;
+
+    &>* {
+        display: -moz-inline-box;
+        display: inline-block;
+        border: 1px dotted transparent;
+        vertical-align: middle;
+    }
+
+    // Expand the first label a bit so the table (hopefully)
+    // does not reshape as columns are selected.
+    &:first-child {
+        margin-right: 1.75em;
+        padding-right: 2px;
+    }
+
+    &:active { color: $linkactivecolour; }
+    &:first-child:active>span, &~label:active>.svg {
+        border-color: $linkactivecolour;
+        @at-root { @supports (outline-style: auto) { & {
+            border-color: transparent;
+            outline: auto $focusringcolour;
+        }}}
+    }
+
+    .svg {
+        margin-left: 0.25em;
+    }
+
+    .svg, svg, img.svgfallback {
+        height: 1.5em;
+        width: auto;
+    }
+    .svg svg { width: 1.5em; }
+}
+
+table.filelist {
+    &>*>tr>*:first-child {
+        &+* { width: 50%; }
+        // chrome doesn't like width: 0 for some reason
+        width: 0.1px;
+    }
+
+    tbody {
+        .svg, svg, img.svgfallback {
+            vertical-align: middle;
+            height: 1.5em;
+            width: auto;
+        }
+
+        .svg {
+            svg { width: 1.5em; }
+            display: inline-block;
+        }
+    }
+}
+
 // Site header rules
 #breadcrumbs>*, #sitetitle>* { font-size: 0.8em; }
 #breadcrumbs {
@@ -173,6 +417,8 @@ table.cc {
 #footer p { color: $annotationcolour; }
 #article-info p { font-style: italic; }
 
+.wbr:after { content: "\200b"; }
+
 // "unordered" lists with explicit ordering in content
 ul.ordered > {
     li { list-style: none; }