使当前活动侧边栏元素的背景透明
Make the background of the current active sidebar element transparent
我最近创建了这个侧边栏,但是我不知道我应该如何使白色背景(仅当前活动元素的)透明,以便如果主要内容有背景图像,它将显示在侧边栏后面(否则看起来像第二张图,这不是我想要实现的)。
这个侧边栏的工作方式是,如果一个项目是 'active' 它被赋予白色背景颜色(在深色侧边栏之上),它的左边框是圆形的,然后它的 ::after 和 ::在元素绝对定位并给出一个圆角框阴影(也是白色)之前,它给出了圆角右角的外观。
The sidebar with a white background
The sidebar with an image as a background (not what I was looking for)
An example of how it should look like, using mix-blend-mode (This is still not what I'm looking for too many things have a semi-transparent background)
我已经用 mix-blend-mode 创建了一个半工作版本,但是这并没有做我想做的一切(它还改变了其他元素的颜色,那些不是'活跃)。
我也尝试过使用 mask 和 clip 属性进行试验,并且我很确定更可靠的解决方案需要其中之一,但是我不确定我将如何去做。
如果有人知道如何让我知道,我将不胜感激。提前致谢!
代码(苗条):
<script lang="ts">
import { Ripple } from '$lib/ripple/Ripple';
import { isThemeDark } from '$lib/theme';
import { Tooltip } from '$lib/tooltip/Tooltip';
// The props for the background and foreground colors
export let backgroundColorLight: string = 'rgb(30 41 59)';
export let foreColorLight: string = 'white';
export let backgroundColorDark: string = 'rgb(241, 245, 241)';
export let foreColorDark: string = 'rgb(30 41 59)';
let sidebar: HTMLElement;
// Depending on the theme sets the color
onMount(() => {
if ($isThemeDark) {
sidebar.style.setProperty('--forecolor', foreColorDark);
sidebar.style.setProperty('--background-color', backgroundColorDark);
} else {
sidebar.style.setProperty('--forecolor', foreColorLight);
sidebar.style.setProperty('--background-color', backgroundColorLight);
}
});
// The Material Design Icons
import { mdiCog, mdiExitToApp, mdiHomeOutline, mdiMenu, mdiViewDashboard } from '@mdi/js';
import { onMount } from 'svelte';
import MdiIcon from './MdiIcon.svelte';
let open = false;
// The sidebar items (apart from the burger menu and the logout button)
let sidebarItems: {
label: string;
iconPath: string;
path: string;
}[] = [
{
label: 'Home',
iconPath: mdiHomeOutline,
path: '/'
},
{
label: 'Dashboard',
iconPath: mdiViewDashboard,
path: '/dashboard'
},
{
label: 'Settings',
iconPath: mdiCog,
path: '/account/settings'
}
];
</script>
<!--The sidebar code-->
<!--use:Ripple and use:Tooltip don't matter for this question so I haven't included the code.-->
<aside class="sidebar" class:open bind:this={sidebar}>
<button class="sidebar-item">
<span
class="sidebar-icon"
on:mousedown={() => {
open = !open;
}}
use:Ripple={{ backgroundColor: 'white' }}><MdiIcon path={mdiMenu} /></span
>
</button>
<!--Loops through the sidebar items and places an <a> for each one-->
{#each sidebarItems as item}
<a class="sidebar-item" class:active={window.location.pathname == item.path} href={item.path}>
<span
class="sidebar-icon"
use:Tooltip={{
tippy: { content: item.label, arrow: false, placement: 'right' },
canShow: !open
}}
use:Ripple={{ backgroundColor: 'white' }}><MdiIcon path={item.iconPath} /></span
>
<p class="sidebar-text">{item.label}</p>
</a>
{/each}
<div class="sidebar-item">
<span
class="sidebar-icon"
use:Tooltip={{
tippy: { content: 'Log out', arrow: false, placement: 'right' },
canShow: !open
}}
use:Ripple={{ backgroundColor: 'white' }}><MdiIcon path={mdiExitToApp} /></span
>
<p class="sidebar-text">Log out</p>
</div>
</aside>
<style lang="scss">
.sidebar {
padding: 0;
color: var(--forecolor);
background-color: var(--background-color);
margin: 0;
width: 5rem;
height: 100vh;
position: fixed;
z-index: 100;
display: flex;
flex-direction: column;
transition: 0.2s ease;
}
.sidebar.open {
width: 16rem;
}
.sidebar-item {
text-decoration: none;
display: flex;
position: relative;
align-items: center;
height: 5rem;
// This is what makes the left border rounded
border-top-left-radius: 16px;
border-bottom-left-radius: 16px;
}
.sidebar-item:nth-last-child(1) {
margin-top: auto;
}
.sidebar-item.active {
margin-left: 0.2rem;
color: var(--background-color);
background-color: var(--forecolor);
// The ::before and ::after are absolutely positioned and a box shadow is given to them to make the right white rounded border for active elements
&::before,
&::after {
content: '';
position: absolute;
right: 0;
width: 30px;
height: 30px;
border-radius: 50%;
}
&::before {
top: -30px;
clip-path: polygon(0% 100%, 100% 0%, 100% 100%);
box-shadow: 15px 15px 0 var(--forecolor);
}
&::after {
bottom: -30px;
box-shadow: 15px -15px 0 var(--forecolor);
clip-path: polygon(0% 0%, 100% 0%, 100% 100%);
}
}
// Secondary code, just to prevent the sidebar icons from looking crazy, and to make it so if the sidebar is closed the text won't show
.sidebar-icon {
width: 3.2rem;
height: 3.2rem;
display: flex;
flex-shrink: 0;
border-radius: 50%;
padding: 0.6rem;
margin: -0.6rem 0.9rem;
}
.sidebar-text {
display: none;
}
.sidebar.open .sidebar-text {
display: block;
}
</style>
我已经看过其他 Whosebug 问题,但是 none 中讨论的只是让部分背景透明,而不是整个背景。
这是一个相当复杂的解决方案,可能仍需要根据您的目的进行一些调整,但希望它符合您的需求。本质上,您需要活动元素的背景是透明的。如果没有圆形切口,这将不是问题。
我的解决方案涉及一组伪元素来覆盖隐藏部分。一个用于顶部,一个用于底部,另一个在左侧的包装纸中。尽管如此,元素本身变得相当大。
编辑:我无法使此处的预览正常工作,所以这是我的 pen。 (编辑 2:现在有效。)
/* Just some setup for the example */
body {
margin: 0;
}
.page {
background: url('https://i.ibb.co/jzfvkR8/wp5961294-aesthetic-minecraft-pc-wallpapers.png');
height: 300px;
}
.sidebar {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
width: 64px;
}
.sidebar::after {
content: '';
display: block;
flex: 1 0 auto;
background: white;
width: 100%;
}
/* Relevant stuff */
.item {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex: 0 0 auto;
background: white;
font-weight: 700;
}
/* Rounded corners top/bottom */
.item::before,
.item::after {
content: '';
display: block;
background: white;
height: 16px;
width: 100%;
}
/* Bottom-right rounded corner for top pseudo-element */
.item.active::before {
border-radius: 0 0 16px 0;
}
/* Top-right rounded corner for bottom pseudo-element */
.item.active::after {
border-radius: 0 16px 0 0;
}
/* Account for top/bottom pseudo-element space */
.item > div {
padding: 16px 0;
}
/* Let background image show through */
.item.active {
background: none;
}
/* Rounded inset corners on the left side */
.item.active > div::before {
/* Make sure to not block the interactive menu item */
pointer-events: none;
content: '';
display: block;
position: absolute;
top: 16px;
left: 1px;
background: transparent;
border-radius: 16px 0 0 16px;
/* Account for top/bottom pseudo-elements */
height: calc(100% - 32px);
width: 16px;
box-shadow: -16px 0 0 16px #ffffff;
}
<div class="page">
<div class="sidebar">
<div class="item">
<div>FOO</div>
</div>
<div class="item active">
<div>BAR</div>
</div>
<div class="item">
<div>BAZ</div>
</div>
</div>
</div>
多亏了 Tetrakern 的回答,我才能够弄清楚我做错了什么。经过一些修补后,我找到了一个解决方案,它实现了我需要的一切,同时也避免了对元素本身有很大的填充。
我对原始设计所做的更改:
- 使用 .sidebar::after 使侧边栏的底部中间具有白色背景色。
- 从 .sidebar
中删除了 color: 和 background-color: 属性
- 删除了用于呈现圆角边框的旧代码
- 用JavaScript到select上一个和下一个children(我本来可以用css来下一个child但是前一个会使用 :has 这是实验性的,所以我选择坚持使用 JS),然后给那些边界半径。
- 使用 .sidebar-item.active::before 来创建我想要的左圆角边框。
它并不完美(因为我制作它只是为了展示新代码的样子),但它确实有效 ;-)
HTML:
<!-- Inter Font -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" />
<!--Code-->
<div class="page">
<aside class="sidebar">
<div class="sidebar-menu">Menu</div>
<div class="sidebar-item">
<p class="sidebar-text">Home</p>
</div>
<div class="sidebar-item active">
<p class="sidebar-text">View</p>
</div>
<div class="sidebar-item">
<p class="sidebar-text">Quit</p>
</div>
<div class="sidebar-item">
<p class="sidebar-text">Extra</p>
</div>
</aside>
</div>
CSS:
body {
margin: 0;
padding: 0;
}
.page {
font-family: "Inter";
width: 100%;
height: 100vh;
background-size: cover;
background-image: linear-gradient(
rgba(0, 23, 238, 0.63),
rgba(48, 0, 239, 0.4)
),
url("https://cdn.discordapp.com/attachments/533643380790394881/912783535067254824/index-background-light.jpg");
}
.sidebar {
padding: 0;
margin: 0;
width: 5rem;
height: 100vh;
position: fixed;
z-index: 100;
display: flex;
flex-direction: column;
}
.sidebar::after {
content: "";
display: block;
flex: 1 0 auto;
background: white;
width: 100%;
}
.sidebar-menu {
text-decoration: none;
background-color: white;
display: flex;
position: relative;
align-items: center;
justify-content: center;
height: 2.5rem;
padding: 1rem 0rem;
}
.sidebar-item {
text-decoration: none;
background-color: white;
display: flex;
position: relative;
align-items: center;
justify-content: center;
height: 2.5rem;
padding: 1rem 0rem;
}
.sidebar-item.active {
color: white;
background-color: transparent;
}
.sidebar-item.active::before {
content: "";
display: block;
position: absolute;
left: 2px;
background: transparent;
border-radius: 16px 0 0 16px;
height: 100%;
width: 16px;
box-shadow: -16px 0 0 16px #fff;
}
JS:
let activeGuy = document.querySelector(".sidebar-item.active");
let sidebarItems = document.querySelectorAll(".sidebar > *");
for (let i = 0; i < sidebarItems.length; i++) {
sidebarItems[i].addEventListener("mouseenter", (ev) => {
activeGuy.classList.remove("active");
activeGuy = ev.target;
activeGuy.classList.add("active");
calculateBorderRadius();
});
}
calculateBorderRadius();
function calculateBorderRadius() {
for (let i = 0; i < sidebarItems.length; i++) {
sidebarItems[i].style.borderRadius = "0";
}
let prev = activeGuy.previousElementSibling;
let next = activeGuy.nextElementSibling;
prev.style.borderBottomRightRadius = "20px";
next.style.borderTopRightRadius = "20px";
}
我最近创建了这个侧边栏,但是我不知道我应该如何使白色背景(仅当前活动元素的)透明,以便如果主要内容有背景图像,它将显示在侧边栏后面(否则看起来像第二张图,这不是我想要实现的)。
这个侧边栏的工作方式是,如果一个项目是 'active' 它被赋予白色背景颜色(在深色侧边栏之上),它的左边框是圆形的,然后它的 ::after 和 ::在元素绝对定位并给出一个圆角框阴影(也是白色)之前,它给出了圆角右角的外观。
The sidebar with a white background
The sidebar with an image as a background (not what I was looking for)
An example of how it should look like, using mix-blend-mode (This is still not what I'm looking for too many things have a semi-transparent background)
我已经用 mix-blend-mode 创建了一个半工作版本,但是这并没有做我想做的一切(它还改变了其他元素的颜色,那些不是'活跃)。 我也尝试过使用 mask 和 clip 属性进行试验,并且我很确定更可靠的解决方案需要其中之一,但是我不确定我将如何去做。
如果有人知道如何让我知道,我将不胜感激。提前致谢!
代码(苗条):
<script lang="ts">
import { Ripple } from '$lib/ripple/Ripple';
import { isThemeDark } from '$lib/theme';
import { Tooltip } from '$lib/tooltip/Tooltip';
// The props for the background and foreground colors
export let backgroundColorLight: string = 'rgb(30 41 59)';
export let foreColorLight: string = 'white';
export let backgroundColorDark: string = 'rgb(241, 245, 241)';
export let foreColorDark: string = 'rgb(30 41 59)';
let sidebar: HTMLElement;
// Depending on the theme sets the color
onMount(() => {
if ($isThemeDark) {
sidebar.style.setProperty('--forecolor', foreColorDark);
sidebar.style.setProperty('--background-color', backgroundColorDark);
} else {
sidebar.style.setProperty('--forecolor', foreColorLight);
sidebar.style.setProperty('--background-color', backgroundColorLight);
}
});
// The Material Design Icons
import { mdiCog, mdiExitToApp, mdiHomeOutline, mdiMenu, mdiViewDashboard } from '@mdi/js';
import { onMount } from 'svelte';
import MdiIcon from './MdiIcon.svelte';
let open = false;
// The sidebar items (apart from the burger menu and the logout button)
let sidebarItems: {
label: string;
iconPath: string;
path: string;
}[] = [
{
label: 'Home',
iconPath: mdiHomeOutline,
path: '/'
},
{
label: 'Dashboard',
iconPath: mdiViewDashboard,
path: '/dashboard'
},
{
label: 'Settings',
iconPath: mdiCog,
path: '/account/settings'
}
];
</script>
<!--The sidebar code-->
<!--use:Ripple and use:Tooltip don't matter for this question so I haven't included the code.-->
<aside class="sidebar" class:open bind:this={sidebar}>
<button class="sidebar-item">
<span
class="sidebar-icon"
on:mousedown={() => {
open = !open;
}}
use:Ripple={{ backgroundColor: 'white' }}><MdiIcon path={mdiMenu} /></span
>
</button>
<!--Loops through the sidebar items and places an <a> for each one-->
{#each sidebarItems as item}
<a class="sidebar-item" class:active={window.location.pathname == item.path} href={item.path}>
<span
class="sidebar-icon"
use:Tooltip={{
tippy: { content: item.label, arrow: false, placement: 'right' },
canShow: !open
}}
use:Ripple={{ backgroundColor: 'white' }}><MdiIcon path={item.iconPath} /></span
>
<p class="sidebar-text">{item.label}</p>
</a>
{/each}
<div class="sidebar-item">
<span
class="sidebar-icon"
use:Tooltip={{
tippy: { content: 'Log out', arrow: false, placement: 'right' },
canShow: !open
}}
use:Ripple={{ backgroundColor: 'white' }}><MdiIcon path={mdiExitToApp} /></span
>
<p class="sidebar-text">Log out</p>
</div>
</aside>
<style lang="scss">
.sidebar {
padding: 0;
color: var(--forecolor);
background-color: var(--background-color);
margin: 0;
width: 5rem;
height: 100vh;
position: fixed;
z-index: 100;
display: flex;
flex-direction: column;
transition: 0.2s ease;
}
.sidebar.open {
width: 16rem;
}
.sidebar-item {
text-decoration: none;
display: flex;
position: relative;
align-items: center;
height: 5rem;
// This is what makes the left border rounded
border-top-left-radius: 16px;
border-bottom-left-radius: 16px;
}
.sidebar-item:nth-last-child(1) {
margin-top: auto;
}
.sidebar-item.active {
margin-left: 0.2rem;
color: var(--background-color);
background-color: var(--forecolor);
// The ::before and ::after are absolutely positioned and a box shadow is given to them to make the right white rounded border for active elements
&::before,
&::after {
content: '';
position: absolute;
right: 0;
width: 30px;
height: 30px;
border-radius: 50%;
}
&::before {
top: -30px;
clip-path: polygon(0% 100%, 100% 0%, 100% 100%);
box-shadow: 15px 15px 0 var(--forecolor);
}
&::after {
bottom: -30px;
box-shadow: 15px -15px 0 var(--forecolor);
clip-path: polygon(0% 0%, 100% 0%, 100% 100%);
}
}
// Secondary code, just to prevent the sidebar icons from looking crazy, and to make it so if the sidebar is closed the text won't show
.sidebar-icon {
width: 3.2rem;
height: 3.2rem;
display: flex;
flex-shrink: 0;
border-radius: 50%;
padding: 0.6rem;
margin: -0.6rem 0.9rem;
}
.sidebar-text {
display: none;
}
.sidebar.open .sidebar-text {
display: block;
}
</style>
我已经看过其他 Whosebug 问题,但是 none 中讨论的只是让部分背景透明,而不是整个背景。
这是一个相当复杂的解决方案,可能仍需要根据您的目的进行一些调整,但希望它符合您的需求。本质上,您需要活动元素的背景是透明的。如果没有圆形切口,这将不是问题。
我的解决方案涉及一组伪元素来覆盖隐藏部分。一个用于顶部,一个用于底部,另一个在左侧的包装纸中。尽管如此,元素本身变得相当大。
编辑:我无法使此处的预览正常工作,所以这是我的 pen。 (编辑 2:现在有效。)
/* Just some setup for the example */
body {
margin: 0;
}
.page {
background: url('https://i.ibb.co/jzfvkR8/wp5961294-aesthetic-minecraft-pc-wallpapers.png');
height: 300px;
}
.sidebar {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
width: 64px;
}
.sidebar::after {
content: '';
display: block;
flex: 1 0 auto;
background: white;
width: 100%;
}
/* Relevant stuff */
.item {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex: 0 0 auto;
background: white;
font-weight: 700;
}
/* Rounded corners top/bottom */
.item::before,
.item::after {
content: '';
display: block;
background: white;
height: 16px;
width: 100%;
}
/* Bottom-right rounded corner for top pseudo-element */
.item.active::before {
border-radius: 0 0 16px 0;
}
/* Top-right rounded corner for bottom pseudo-element */
.item.active::after {
border-radius: 0 16px 0 0;
}
/* Account for top/bottom pseudo-element space */
.item > div {
padding: 16px 0;
}
/* Let background image show through */
.item.active {
background: none;
}
/* Rounded inset corners on the left side */
.item.active > div::before {
/* Make sure to not block the interactive menu item */
pointer-events: none;
content: '';
display: block;
position: absolute;
top: 16px;
left: 1px;
background: transparent;
border-radius: 16px 0 0 16px;
/* Account for top/bottom pseudo-elements */
height: calc(100% - 32px);
width: 16px;
box-shadow: -16px 0 0 16px #ffffff;
}
<div class="page">
<div class="sidebar">
<div class="item">
<div>FOO</div>
</div>
<div class="item active">
<div>BAR</div>
</div>
<div class="item">
<div>BAZ</div>
</div>
</div>
</div>
多亏了 Tetrakern 的回答,我才能够弄清楚我做错了什么。经过一些修补后,我找到了一个解决方案,它实现了我需要的一切,同时也避免了对元素本身有很大的填充。 我对原始设计所做的更改:
- 使用 .sidebar::after 使侧边栏的底部中间具有白色背景色。
- 从 .sidebar 中删除了 color: 和 background-color: 属性
- 删除了用于呈现圆角边框的旧代码
- 用JavaScript到select上一个和下一个children(我本来可以用css来下一个child但是前一个会使用 :has 这是实验性的,所以我选择坚持使用 JS),然后给那些边界半径。
- 使用 .sidebar-item.active::before 来创建我想要的左圆角边框。
它并不完美(因为我制作它只是为了展示新代码的样子),但它确实有效 ;-)
HTML:
<!-- Inter Font -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" />
<!--Code-->
<div class="page">
<aside class="sidebar">
<div class="sidebar-menu">Menu</div>
<div class="sidebar-item">
<p class="sidebar-text">Home</p>
</div>
<div class="sidebar-item active">
<p class="sidebar-text">View</p>
</div>
<div class="sidebar-item">
<p class="sidebar-text">Quit</p>
</div>
<div class="sidebar-item">
<p class="sidebar-text">Extra</p>
</div>
</aside>
</div>
CSS:
body {
margin: 0;
padding: 0;
}
.page {
font-family: "Inter";
width: 100%;
height: 100vh;
background-size: cover;
background-image: linear-gradient(
rgba(0, 23, 238, 0.63),
rgba(48, 0, 239, 0.4)
),
url("https://cdn.discordapp.com/attachments/533643380790394881/912783535067254824/index-background-light.jpg");
}
.sidebar {
padding: 0;
margin: 0;
width: 5rem;
height: 100vh;
position: fixed;
z-index: 100;
display: flex;
flex-direction: column;
}
.sidebar::after {
content: "";
display: block;
flex: 1 0 auto;
background: white;
width: 100%;
}
.sidebar-menu {
text-decoration: none;
background-color: white;
display: flex;
position: relative;
align-items: center;
justify-content: center;
height: 2.5rem;
padding: 1rem 0rem;
}
.sidebar-item {
text-decoration: none;
background-color: white;
display: flex;
position: relative;
align-items: center;
justify-content: center;
height: 2.5rem;
padding: 1rem 0rem;
}
.sidebar-item.active {
color: white;
background-color: transparent;
}
.sidebar-item.active::before {
content: "";
display: block;
position: absolute;
left: 2px;
background: transparent;
border-radius: 16px 0 0 16px;
height: 100%;
width: 16px;
box-shadow: -16px 0 0 16px #fff;
}
JS:
let activeGuy = document.querySelector(".sidebar-item.active");
let sidebarItems = document.querySelectorAll(".sidebar > *");
for (let i = 0; i < sidebarItems.length; i++) {
sidebarItems[i].addEventListener("mouseenter", (ev) => {
activeGuy.classList.remove("active");
activeGuy = ev.target;
activeGuy.classList.add("active");
calculateBorderRadius();
});
}
calculateBorderRadius();
function calculateBorderRadius() {
for (let i = 0; i < sidebarItems.length; i++) {
sidebarItems[i].style.borderRadius = "0";
}
let prev = activeGuy.previousElementSibling;
let next = activeGuy.nextElementSibling;
prev.style.borderBottomRightRadius = "20px";
next.style.borderTopRightRadius = "20px";
}