使当前活动侧边栏元素的背景透明



我最近创建了这个侧边栏,但我不知道应该如何使白色背景(仅是当前活动元素的(透明,以便如果主要内容有背景图像,它将显示在侧边栏后面(否则它看起来像第二张图,这不是我想要实现的(。

这个侧边栏的工作方式是,如果一个项目是"活动的",它会被赋予白色背景色(在深色侧边栏之上(,它的左边框是圆形的,然后它的::after和::before元素被绝对定位,并被赋予圆形的框阴影(也是白色(,看起来像圆角的右角。

带有白色背景的侧边栏

以图像为背景的侧边栏(不是我想要的(

使用混合混合模式(这仍然不是我想要的,太多东西都有半透明背景(

我已经创建了一个具有混合混合模式的半工作版本,但这并不是我想要的一切(它还更改了其他元素的颜色,即未激活的元素(。我也尝试过测试掩模和夹子的特性,我很确定一个更可靠的解决方案需要其中一个,但我不确定我会怎么做。

如果有人知道怎么做,如果你能告诉我,我将不胜感激。提前感谢!

代码(苗条(:

<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>

我已经研究了其他stackoverflow问题,但没有一个问题只讨论了部分背景是透明的,而不是整个背景。

这是一个相当复杂的解决方案,可能仍需要对其进行一些调整,但希望它能满足您的需求。从本质上讲,您需要活动元素的背景是透明的。如果不是四舍五入的话,这不会是个问题。

我的解决方案包括一组伪元素来覆盖隐藏的部分。一个用于顶部,一个用于底部,另一个在包装内用于左侧。然而,元素本身也因此变得相当大。

编辑:我很难让这里的预览正常工作,所以这是我的笔。(编辑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的回答,我才弄清楚自己做错了什么。经过一些修补,我找到了一个解决方案,它实现了我所需要的一切,同时也避免了元素本身有很大的填充。我对我的原始设计所做的更改:

  1. 使用.边栏::after使边栏的底部中间有一个白色的背景色
  2. 删除了侧边栏中的颜色:和背景颜色:属性
  3. 删除了用于呈现圆角边框的旧代码
  4. 使用JavaScript来选择上一个和下一个子项(我本可以为下一个使用css,但上一个会使用:has,这是实验性的,所以我选择为这两个都使用JS(,然后为它们指定边界半径
  5. Used.sidebatem.active::之前创建了我想要的左圆角边框

代码笔

它并不完美(因为我只是为了展示新代码的外观(,但它很有效;-(

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";
}