From 99e24b4134c461c336f6d08f49d193d853325d31 Mon Sep 17 00:00:00 2001 From: undergroundwires Date: Sat, 12 Mar 2022 10:59:28 +0100 Subject: [PATCH] Improve touch like hover on devices without mouse This commit improves mobile support. `:hover` CSS selector is not mobile friendly because there is typically no mouse support on mobile. This commit make hover behavior to become active during touch on mobile. `:hover` selector is emulated on mobile devices. But this emulated behavior is not desired. When emulated, the CSS style gets attached when starting touching but does not get removed after stopping touching. This sticky behavior is undesired. This commit solve this issue by using Saas mixing that uses `:active` selector instead of `:hover` when `:hover` is not really supported but emulated. --- src/presentation/assets/styles/_globals.scss | 4 ++-- src/presentation/assets/styles/_mixins.scss | 16 ++++++++++++++++ src/presentation/assets/styles/main.scss | 1 + .../styles/third-party-extensions/_tree.scss | 4 +++- .../components/Code/CodeButtons/Code.vue | 4 ++-- .../components/Code/CodeButtons/IconButton.vue | 9 ++++++--- .../Scripts/Menu/MenuOptionListItem.vue | 4 ++-- .../components/Scripts/Slider/Handle.vue | 2 +- .../Scripts/View/Cards/CardListItem.vue | 8 ++++---- .../SelectableTree/Node/DocumentationUrls.vue | 2 +- .../components/Scripts/View/TheScriptsView.vue | 2 +- src/presentation/components/Shared/Dialog.vue | 2 +- 12 files changed, 40 insertions(+), 18 deletions(-) create mode 100644 src/presentation/assets/styles/_mixins.scss diff --git a/src/presentation/assets/styles/_globals.scss b/src/presentation/assets/styles/_globals.scss index 72cfbcfb..ba24dfa9 100644 --- a/src/presentation/assets/styles/_globals.scss +++ b/src/presentation/assets/styles/_globals.scss @@ -4,7 +4,7 @@ @use "@/presentation/assets/styles/colors" as *; @use "@/presentation/assets/styles/fonts" as *; - +@use "@/presentation/assets/styles/mixins" as *; * { box-sizing: border-box; @@ -14,7 +14,7 @@ a { color:inherit; text-decoration: underline; cursor: pointer; - &:hover { + @include hover-or-touch { color: $color-primary; } } diff --git a/src/presentation/assets/styles/_mixins.scss b/src/presentation/assets/styles/_mixins.scss new file mode 100644 index 00000000..aedc9c7c --- /dev/null +++ b/src/presentation/assets/styles/_mixins.scss @@ -0,0 +1,16 @@ +@mixin hover-or-touch($selector-suffix: '', $selector-prefix: '&') { + @media (hover: hover) { + /* We only do this if hover is truly supported; otherwise the emulator in mobile + keeps hovered style in-place even after touching, making it sticky. */ + #{$selector-prefix}:hover #{$selector-suffix} { + @content; + } + } + @media (hover: none) { + /* We only do this if hover is not supported,otherwise the desktop behavior is not + as desired; it does not get activated on hover but only during click/touch. */ + #{$selector-prefix}:active #{$selector-suffix} { + @content; + } + } +} diff --git a/src/presentation/assets/styles/main.scss b/src/presentation/assets/styles/main.scss index 0b3490a8..e869bc4c 100644 --- a/src/presentation/assets/styles/main.scss +++ b/src/presentation/assets/styles/main.scss @@ -4,6 +4,7 @@ @forward "./media"; @forward "./colors"; @forward "./globals"; +@forward "./mixins"; @forward "./components/card"; diff --git a/src/presentation/assets/styles/third-party-extensions/_tree.scss b/src/presentation/assets/styles/third-party-extensions/_tree.scss index 1e3b785b..78a5a339 100644 --- a/src/presentation/assets/styles/third-party-extensions/_tree.scss +++ b/src/presentation/assets/styles/third-party-extensions/_tree.scss @@ -1,5 +1,6 @@ // Overrides base styling for LiquorTree @use "@/presentation/assets/styles/colors" as *; +@use "@/presentation/assets/styles/mixins" as *; $color-tree-bg : $color-primary-darker; $color-node-arrow : $color-on-primary; @@ -23,9 +24,10 @@ $color-node-checkbox-tick-checked : $color-on-secondary; text-transform: uppercase; font-size: 1.5em; } - &:hover { + @include hover-or-touch { background: $color-node-hover-bg !important; } + background: $color-tree-bg !important; // If not styled, it gets white background on mobile. } &.selected { // When using keyboard navigation it highlights current item and its child items background: $color-node-keyboard-bg; diff --git a/src/presentation/components/Code/CodeButtons/Code.vue b/src/presentation/components/Code/CodeButtons/Code.vue index 27b4ee54..8d97476d 100644 --- a/src/presentation/components/Code/CodeButtons/Code.vue +++ b/src/presentation/components/Code/CodeButtons/Code.vue @@ -43,8 +43,8 @@ export default class Code extends Vue { .copy-button { margin-left: 1rem; cursor: pointer; - &:hover { - color: $color-primary; + @include hover-or-touch { + color: $color-primary; } } code { diff --git a/src/presentation/components/Code/CodeButtons/IconButton.vue b/src/presentation/components/Code/CodeButtons/IconButton.vue index 60254c52..5be2b8c9 100644 --- a/src/presentation/components/Code/CodeButtons/IconButton.vue +++ b/src/presentation/components/Code/CodeButtons/IconButton.vue @@ -45,14 +45,14 @@ export default class IconButton extends Vue { cursor: pointer; width: 10%; min-width: 90px; - &:hover { + @include hover-or-touch { background: $color-surface; box-shadow: 0px 2px 10px 5px $color-secondary; } - &:hover>&__text { + @include hover-or-touch('>&__text') { display: block; } - &:hover>&__icon { + @include hover-or-touch('>&__icon') { display: none; } &__text { @@ -62,6 +62,9 @@ export default class IconButton extends Vue { color: $color-primary; font-weight: 500; line-height: 1.1; + @include hover-or-touch { + display: block; + } } } diff --git a/src/presentation/components/Scripts/Menu/MenuOptionListItem.vue b/src/presentation/components/Scripts/Menu/MenuOptionListItem.vue index 4360b35a..214b6896 100644 --- a/src/presentation/components/Scripts/Menu/MenuOptionListItem.vue +++ b/src/presentation/components/Scripts/Menu/MenuOptionListItem.vue @@ -29,8 +29,8 @@ export default class MenuOptionListItem extends Vue { @use "@/presentation/assets/styles/main" as *; .enabled { - cursor: pointer; - &:hover { + cursor: pointer; + @include hover-or-touch { font-weight:bold; text-decoration:underline; } diff --git a/src/presentation/components/Scripts/Slider/Handle.vue b/src/presentation/components/Scripts/Slider/Handle.vue index e35881a4..d060d418 100644 --- a/src/presentation/components/Scripts/Slider/Handle.vue +++ b/src/presentation/components/Scripts/Slider/Handle.vue @@ -56,7 +56,7 @@ $color-hover : $color-primary; display: flex; flex-direction: column; align-items: center; - &:hover { + @include hover-or-touch { .line { background: $color-hover; } diff --git a/src/presentation/components/Scripts/View/Cards/CardListItem.vue b/src/presentation/components/Scripts/View/Cards/CardListItem.vue index 263908db..078b7e66 100644 --- a/src/presentation/components/Scripts/View/Cards/CardListItem.vue +++ b/src/presentation/components/Scripts/View/Cards/CardListItem.vue @@ -144,7 +144,7 @@ $card-horizontal-gap : $card-gap; flex-direction: column; justify-content: center; - &:hover { + @include hover-or-touch { background-color: $color-secondary; color: $color-on-secondary; transform: scale(1.05); @@ -189,7 +189,7 @@ $card-horizontal-gap : $card-gap; margin-right: 0.25em; cursor: pointer; color: $color-primary-light; - &:hover { + @include hover-or-touch { color: $color-primary; } } @@ -236,7 +236,7 @@ $card-horizontal-gap : $card-gap; opacity: 1; } - &:hover { + @include hover-or-touch { .card__inner { transform: scale(1); } @@ -251,7 +251,7 @@ $card-horizontal-gap : $card-gap; transform: scale(0.95); } - &:hover { + @include hover-or-touch { .card__inner { background-color: $color-primary; transform: scale(1); diff --git a/src/presentation/components/Scripts/View/ScriptsTree/SelectableTree/Node/DocumentationUrls.vue b/src/presentation/components/Scripts/View/ScriptsTree/SelectableTree/Node/DocumentationUrls.vue index d3be7646..8ea8f1d6 100644 --- a/src/presentation/components/Scripts/View/ScriptsTree/SelectableTree/Node/DocumentationUrls.vue +++ b/src/presentation/components/Scripts/View/ScriptsTree/SelectableTree/Node/DocumentationUrls.vue @@ -35,7 +35,7 @@ export default class DocumentationUrls extends Vue { color: $color-primary; cursor: pointer; vertical-align: middle; - &:hover { + @include hover-or-touch { color: $color-primary-darker; } &:not(:first-child) { diff --git a/src/presentation/components/Scripts/View/TheScriptsView.vue b/src/presentation/components/Scripts/View/TheScriptsView.vue index 5643b452..e5a0ce34 100644 --- a/src/presentation/components/Scripts/View/TheScriptsView.vue +++ b/src/presentation/components/Scripts/View/TheScriptsView.vue @@ -140,7 +140,7 @@ $margin-inner: 4px; cursor: pointer; font-size: 1.25em; margin-left: 0.25rem; - &:hover { + @include hover-or-touch { color: $color-primary-dark; } } diff --git a/src/presentation/components/Shared/Dialog.vue b/src/presentation/components/Shared/Dialog.vue index 11379983..f8f01ab7 100644 --- a/src/presentation/components/Shared/Dialog.vue +++ b/src/presentation/components/Shared/Dialog.vue @@ -53,7 +53,7 @@ export default class Dialog extends Vue { margin-right: 0.25em; align-self: flex-start; cursor: pointer; - &:hover { + @include hover-or-touch { color: $color-primary; } }