Skip to content

Instantly share code, notes, and snippets.

@akbertram
Last active October 17, 2019 13:59
Show Gist options
  • Save akbertram/b8181d264d64ff12b60042db04dfa9ca to your computer and use it in GitHub Desktop.
Save akbertram/b8181d264d64ff12b60042db04dfa9ca to your computer and use it in GitHub Desktop.
ColumnMenu Styles
/*
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