Instantly share code, notes, and snippets.
Last active
October 17, 2019 13:59
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save akbertram/b8181d264d64ff12b60042db04dfa9ca to your computer and use it in GitHub Desktop.
ColumnMenu Styles
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Column Dropdown Menu | |
Column menus have slightly different requirements from other drop down menus. | |
Here are a few requirements: | |
1. Anchor vertically to the top of the datatable body | |
2. Center horizontally to the center of the column filter button, but constrained to the | |
left and right edges of the data table body. | |
3. Size height according to the content, but constrained to the bottom edge of the data table body. | |
4. Respond to changes in the width and height of the content in the menu. | |
5. Respond to changes in the height of the data table. | |
We can achieve this by (ab)using Flexbox, which offers a way to set contraints | |
along a single dimension. | |
We start by creating a container with display: flex and three children: | |
1. A left gutter | |
2. The menu body itself | |
3. A right gutter. | |
We define the width of the left as the horizontal $x position, and the width of the right | |
gutter the remaining space using calc(100% - $x). | |
If the menu had no content, then it would like this: | |
+ | |
| Anchor here ($x) | |
| | |
v | |
+-----------------------------------------------------+++-------------------------------+ | |
| | | | | |
| Left gutter: | | Right gutter | | |
| | | | | |
| width: $x | | width: calc(100% - $x) | | |
| flex-shrink: 21 | | flex-shrink: 100 | | |
| | | | | |
| | | | | |
+-----------------------------------------------------+-+-------------------------------+ | |
But of course, we want to handle the case where the body has content and has a non zero width. | |
To allow the menu body to grow according to its content, we set the flex-shrink of the two gutters. | |
To keep the menu centered, we set the values of flex-shrink *inversely proportional to the | |
relative size* of the gutters. In the diagram above, the anchor $x is farther from the left edge, | |
so the left gutter is larger, and has a smaller flex-shrink value so that shrinks slower | |
than the right gutter and we maintain the central position of the menu. | |
Note that this is not entirely responsive to changes to the container width. We can use the | |
CSS calc() function to size the right gutter appropriately, but calculating the flex-shrink | |
value of the left gutter does not appear possible. It should look like this: | |
flex-shrink: calc( (100% / 150px) - 1 * 100 ) | |
But Chrome does not appear to allow the use of percentages in the flex-shrink property. | |
This means that the menu width does respond correctly to changes in the container width, | |
but the menu's alignment will be increasingly off center as the container width changes | |
because we are not able to dynamically update the flex-shrink value of the left gutter. | |
Here is the proof-of-concept: | |
https://codepen.io/akbertram/pen/JjjKNrX | |
*/ | |
.datatable__colmenu { | |
// Position the container absolutely | |
// to cover the whole data table. At runtime, we | |
// need to measure the height of the datatable__header element | |
// and use that as the top. | |
position: absolute; | |
/* top: set at runtime to $header.height */ | |
left: 0; | |
right: 0; | |
bottom: 0; | |
display: flex; | |
align-items: flex-start; | |
z-index: $z-level-dropdown; | |
} | |
.datatable__colmenu__gutter { | |
height: 0; | |
flex-grow: 0; | |
// Provides a minimum space between the menu | |
// and the edge of the container | |
min-width: 0.5rem; | |
} | |
.datatable__colmenu__body { | |
background-color: $black; | |
color: $white; | |
font-weight: bold; | |
font-size: 0.875rem; | |
// Prioritize this element's width infinitely | |
// more than the two gutters | |
flex-grow: 1000; | |
// Allow the menu to shrink if it exceeds the width of the container. | |
flex-shrink: 1; | |
// Set the width of the menu to the maximum | |
// required by the content | |
width: max-content; | |
width: -moz-max-content; | |
// Restrict to the height of the container, | |
// and scroll vertically if neccessary | |
max-height: 100%; | |
overflow-y: auto; | |
@include darkscrollbars(); | |
} | |
.datatable__colmenu__arrow { | |
display: block; | |
position: absolute; | |
/* left: set at runtime to $x */ | |
top: -0.5rem; | |
/* rtl:ignore */ | |
transform: translateX(-50%); | |
border-bottom: 0.5rem solid $black; | |
border-left: 0.5rem solid transparent; | |
border-right: 0.5rem solid transparent; | |
} | |
// Somehow avoids the buttons with padding from | |
// being squeezed | |
.datatable__colmenu__body .button { | |
width: max-content; | |
width: -moz-max-content; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment