From 0436507574704d700a73eccd0b82b9f7d0a6c02e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 25 Mar 2020 19:24:32 +0100 Subject: [PATCH] use transparent scrollbars on not hover to emulate scrolbar on hover allows us to get rid of the margin-right hack as well --- res/css/structures/_AutoHideScrollbar.scss | 78 +++++-------------- .../structures/AutoHideScrollbar.js | 57 +------------- 2 files changed, 21 insertions(+), 114 deletions(-) diff --git a/res/css/structures/_AutoHideScrollbar.scss b/res/css/structures/_AutoHideScrollbar.scss index 6e4484157c..3d91293c98 100644 --- a/res/css/structures/_AutoHideScrollbar.scss +++ b/res/css/structures/_AutoHideScrollbar.scss @@ -14,76 +14,34 @@ See the License for the specific language governing permissions and limitations under the License. */ -/* This file has CSS for both native and non-native scrollbars in an order - * that's fairly logical to read but duplicates a selector to separate the - * hiding/showing from the sizing. - */ -/* stylelint-disable no-duplicate-selectors */ - -/* -1. for browsers that support native overlay auto-hiding scrollbars -*/ .mx_AutoHideScrollbar { overflow-x: hidden; overflow-y: auto; + overflow-y: overlay; // where supported -ms-overflow-style: -ms-autohiding-scrollbar; -} -/* -2. webkit also supports overflow:overlay where the scrollbars don't take any space -in the layout but they don't autohide, so do that only on hover -*/ -body.mx_scrollbar_overlay_noautohide .mx_AutoHideScrollbar { - overflow-y: hidden; -} -body.mx_scrollbar_overlay_noautohide .mx_AutoHideScrollbar:hover { - overflow-y: overlay; -} -/* -3. as a last fallback, compensate for the scrollbar taking up space in the layout -by having giving the child element (.mx_AutoHideScrollbar_offset) a -negative right margin of the width of the scrollbar when the container -is overflowing. This is what Firefox ends up using. Overflow is detected -in javascript, and adds the mx_AutoHideScrollbar_overflow class to the container. -This only works in Firefox, which should be fine as this fallback is only needed there. -*/ -body.mx_scrollbar_nooverlay { - .mx_AutoHideScrollbar { - overflow-y: hidden; + &::-webkit-scrollbar { + width: 6px; + height: 6px; + background-color: transparent; } - .mx_AutoHideScrollbar:hover { - overflow-y: auto; + &::-webkit-scrollbar-thumb { + border-radius: 3px; + background-color: transparent; } - /* - offset scrollbar width with negative margin-right - - include before and after psuedo-elements here so they can - be used to do something interesting like scroll-indicating - gradients (see IndicatorScrollBar) - */ - .mx_AutoHideScrollbar:hover.mx_AutoHideScrollbar_overflow > .mx_AutoHideScrollbar_offset, - .mx_AutoHideScrollbar:hover.mx_AutoHideScrollbar_overflow::before, - .mx_AutoHideScrollbar:hover.mx_AutoHideScrollbar_overflow::after { - margin-right: calc(-1 * var(--scrollbar-width)); - } -} - -// style the native scrollbars ... -// ... standard css scrollbars (firefox at time of writing) -.mx_AutoHideScrollbar { - scrollbar-color: $scrollbar-thumb-color $scrollbar-track-color; + scrollbar-color: transparent transparent; scrollbar-width: thin; } -// or fallback for webkit browsers -::-webkit-scrollbar { - width: 6px; - height: 6px; - background-color: $scrollbar-track-color; -} -::-webkit-scrollbar-thumb { - background-color: $scrollbar-thumb-color; - border-radius: 3px; +.mx_AutoHideScrollbar:hover { + &::-webkit-scrollbar { + background-color: $scrollbar-track-color; + } + + &::-webkit-scrollbar-thumb { + background-color: $scrollbar-thumb-color; + } + scrollbar-color: $scrollbar-thumb-color $scrollbar-track-color; } diff --git a/src/components/structures/AutoHideScrollbar.js b/src/components/structures/AutoHideScrollbar.js index 3f27f51f18..398b07e2d4 100644 --- a/src/components/structures/AutoHideScrollbar.js +++ b/src/components/structures/AutoHideScrollbar.js @@ -18,7 +18,7 @@ import React from "react"; // derived from code from github.com/noeldelgado/gemini-scrollbar // Copyright (c) Noel Delgado (pixelia.me) -function getScrollbarWidth(alternativeOverflow) { +function getScrollbarWidth() { const div = document.createElement('div'); div.className = 'mx_AutoHideScrollbar'; //to get width of css scrollbar div.style.position = 'absolute'; @@ -26,9 +26,6 @@ function getScrollbarWidth(alternativeOverflow) { div.style.width = '100px'; div.style.height = '100px'; div.style.overflow = "scroll"; - if (alternativeOverflow) { - div.style.overflow = alternativeOverflow; - } div.style.msOverflowStyle = '-ms-autohiding-scrollbar'; document.body.appendChild(div); const scrollbarWidth = (div.offsetWidth - div.clientWidth); @@ -39,18 +36,7 @@ function getScrollbarWidth(alternativeOverflow) { function install() { const scrollbarWidth = getScrollbarWidth(); if (scrollbarWidth !== 0) { - const hasForcedOverlayScrollbar = getScrollbarWidth('overlay') === 0; - // overflow: overlay on webkit doesn't auto hide the scrollbar - if (hasForcedOverlayScrollbar) { - document.body.classList.add("mx_scrollbar_overlay_noautohide"); - } else { - document.body.classList.add("mx_scrollbar_nooverlay"); - const style = document.createElement('style'); - style.type = 'text/css'; - style.innerText = - `body.mx_scrollbar_nooverlay { --scrollbar-width: ${scrollbarWidth}px; }`; - document.head.appendChild(style); - } + document.body.classList.add("mx_scrollbar_noautohide"); } } @@ -67,42 +53,7 @@ const installBodyClassesIfNeeded = (function() { export default class AutoHideScrollbar extends React.Component { constructor(props) { super(props); - this.onOverflow = this.onOverflow.bind(this); - this.onUnderflow = this.onUnderflow.bind(this); this._collectContainerRef = this._collectContainerRef.bind(this); - this._needsOverflowListener = null; - } - - onOverflow() { - this.containerRef.classList.add("mx_AutoHideScrollbar_overflow"); - this.containerRef.classList.remove("mx_AutoHideScrollbar_underflow"); - } - - onUnderflow() { - this.containerRef.classList.remove("mx_AutoHideScrollbar_overflow"); - this.containerRef.classList.add("mx_AutoHideScrollbar_underflow"); - } - - checkOverflow() { - if (!this._needsOverflowListener) { - return; - } - if (this.containerRef.scrollHeight > this.containerRef.clientHeight) { - this.onOverflow(); - } else { - this.onUnderflow(); - } - } - - componentDidUpdate() { - this.checkOverflow(); - } - - componentDidMount() { - installBodyClassesIfNeeded(); - this._needsOverflowListener = - document.body.classList.contains("mx_scrollbar_nooverlay"); - this.checkOverflow(); } _collectContainerRef(ref) { @@ -126,9 +77,7 @@ export default class AutoHideScrollbar extends React.Component { onScroll={this.props.onScroll} onWheel={this.props.onWheel} > -
- { this.props.children } -
+ { this.props.children } ); } }