Skip to content

Commit

Permalink
simplifying the structure of s-expandable and removed outdated styles
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejkonec committed Oct 13, 2022
1 parent a7d91fe commit de71a8e
Showing 1 changed file with 13 additions and 97 deletions.
110 changes: 13 additions & 97 deletions lib/css/components/expandable.less
Original file line number Diff line number Diff line change
@@ -1,104 +1,20 @@
// see http://stackoverflow.com/a/43965099 for how this works:

// Notes on the clip-path stuff: What we would really like is overflow: hidden during the transition,
// but not when the element is expanded. Unfortunately, although the CSS spec provides for it, there's
// no browser support yet for transitioning non-interpolatable properties, and therefore we cannot say
// "change overflow to visible *after* the transition".
//
// So we use clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%), which is essentially the same
// as overflow: hidden, but unlike overflow, clip-path is interpolatable -- but only if the opposite state
// is also a polygon, and has the same vertice count. So our version of overflow: visible is a rectangle
// of 2x2 million pixels, which should be enough for everybody (TM).
//
// At the time of writing, clip-path works in Chrome, Firefox Beta, and Safari (with vendor prefix).
//
// In browsers that do not support this yet, we have to have another way to prevent the expandable content
// from being visible below the bottom edge during the transition, and the best I could come up with is
// transitioning to scaleY(0) with a timing function that's faster than the height-reducing transitions.
// This does kinda look like a deliberate effect, even more so if we also transition to transparency
// (which we therefore do), so I feel it's an okay fallback.
// STACK OVERFLOW
// EXPANDABLE
//
// We still set overflow to hidden in the collapsed state (which also applies to the collapsing transition),
// we just can't do that for the expanding transition.
// This CSS comes from Stacks, our CSS & Pattern library for rapidly building
// Stack Overflow. For documentation of all these classes and how to contribute,
// visit https://stackoverflow.design/
//
// A major drawback of clip-path is that even though the content is clipped (not visible), it will still
// contribute to the document height. This caused a jumping around of the scrollbar (and possibly even
// of the viewport) when the expandable was at the bottom of the page, because once the negative bottom
// margin of the -expandable-group exceeds the actual height, any additional pixels were added on to the
// bottom. The fix is to set the -expandable-group's flex alignment to flex-start, which forces the
// (no longer visible) element itself to remain at the top, thereby forcing the excess pixels to be added
// above the top, not below the bottom. And because extending content above the document top will not do
// anything to the document height, there is no jumping during the transition.

@stacks-internals-s-expandable-transition-duration: 100ms;

// Per the answer referenced above, the component can only guarantee smooth transitions if above a minimum
// height and can only guarantee the element will be hidden is below a maximimum height.
// The minimum height has been set at 10px because that's below the height of a single line of text in an s-description.
@stacks-internal-s-expandable-min-expected-height: 10px;
@stacks-internal-s-expandable-max-expected-height: 1500px;

.s-expandable {
display: flex;
-webkit-clip-path: polygon(-1000000px -1000000px, 1000000px -1000000px, 1000000px 1000000px, -1000000px 1000000px);
clip-path: polygon(-1000000px -1000000px, 1000000px -1000000px, 1000000px 1000000px, -1000000px 1000000px);
align-items: flex-start; // see comment above
transition: clip-path 0s @stacks-internals-s-expandable-transition-duration, -webkit-clip-path 0s @stacks-internals-s-expandable-transition-duration;

&:after {
content: '';
-ms-flex-preferred-size: 0;
flex-basis: 0;
height: @stacks-internal-s-expandable-min-expected-height;
max-height: 0;
transition:
height @stacks-internals-s-expandable-transition-duration linear,
max-height 0s @stacks-internals-s-expandable-transition-duration linear;
}
}

.s-expandable--content {
-ms-flex-preferred-size: 100%;
flex-basis: 100%;
max-height: 1000000px;
margin-bottom: 0;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
transition:
margin-bottom @stacks-internals-s-expandable-transition-duration cubic-bezier(0, 0, 0, 1),
transform @stacks-internals-s-expandable-transition-duration cubic-bezier(1, 0, 1, 1),
opacity @stacks-internals-s-expandable-transition-duration cubic-bezier(1, 0, 1, 1);
}

.s-expandable:not(.is-expanded) {
height: 0;
opacity: 0;
visibility: hidden;
overflow: hidden;
-webkit-clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
transition: none;

.s-expandable--content {
visibility: hidden;
max-height: 0;
margin-bottom: -@stacks-internal-s-expandable-max-expected-height;
opacity: 0;
-webkit-transform: scaleY(0);
transform: scaleY(0);
transition:
margin-bottom @stacks-internals-s-expandable-transition-duration cubic-bezier(1, 0, 1, 1),
visibility 0s @stacks-internals-s-expandable-transition-duration,
max-height 0s @stacks-internals-s-expandable-transition-duration,
transform @stacks-internals-s-expandable-transition-duration cubic-bezier(0, 1, 1, 1),
opacity @stacks-internals-s-expandable-transition-duration cubic-bezier(0, 1, 1, 1);
@supports ((-webkit-clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)) or (clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%))) {
opacity: 1;
-webkit-transform: none;
transform: none;
}
}

&:after {
height: 0;
max-height: @stacks-internal-s-expandable-min-expected-height;
transition: height @stacks-internals-s-expandable-transition-duration linear;
}
}
.s-expandable.is-expanded {
height: auto;
visibility: visible;
opacity: 1;
}

0 comments on commit de71a8e

Please sign in to comment.