mirror of
https://github.com/element-hq/element-web
synced 2024-11-26 11:15:53 +03:00
use transparent scrollbars on not hover to emulate scrolbar on hover
allows us to get rid of the margin-right hack as well
This commit is contained in:
parent
44ce5b5764
commit
0436507574
2 changed files with 21 additions and 114 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import React from "react";
|
|||
|
||||
// derived from code from github.com/noeldelgado/gemini-scrollbar
|
||||
// Copyright (c) Noel Delgado <pixelia.me@gmail.com> (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}
|
||||
>
|
||||
<div className="mx_AutoHideScrollbar_offset">
|
||||
{ this.props.children }
|
||||
</div>
|
||||
{ this.props.children }
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue