Scroll effect (background gradient) - css

I'm trying to make the background scroll on this code instead of the text.
meaning the text with the clipping stays in position and the background scrolls behind it in the page
how can I solve this?
EXAMPLE on codepen:
body {
margin: 0;
background-color: #000;
}
.page {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.container {
height: 100vh;
width: 100%;
overflow-y: scroll;
}
.content {
display: flex;
justify-content: center;
align-items: center;
height: 250vh;
font-size: 96px;
background: linear-gradient(
#000 0%,
#66458e 40%,
#fff 50%,
#66458e 75%,
#000 100%
);
background-clip: text;
-webkit-background-clip: text;
color: transparent;
background-attachment: fixed;
}
.text {
text-align: center;
}
<div class="page">
<div class="container">
<div class="content">
<h1 class="text">TEST</h1>
</div>
</div>
</div>

The way to do this is to have a background div with the linear gradient then overlay the h1 element using position: fixed to stop the text from scrolling.
Rather than using background-clip text, you can to use mix-blend-mode: multiply with white text to bring the background through the text. I've then used a box shadow to mask out the remaining background outside the h1 element. See below
body {
margin: 0;
background-color: #000;
}
.content {
height: 250vh;
background: linear-gradient(
#000 0%,
#66458e 40%,
#fff 50%,
#66458e 75%,
#000 100%
);
}
.text {
margin:0;
position: fixed;
font-size: 8rem;
font-weight: bold;
left:50%;
top:50%;
box-shadow: 0px 0px 0px 200vh black;
color:white;
background-color: black;
mix-blend-mode: multiply;
transform: translate(-50%, -50%);
}
<div class="content">
<h1 class="text">TEST</h1>
</div>

Related

Opacity for only a part of background image - CSS

Do you maybe know how (and if) I can add an opacity for the background image but only to PART of it?
The effect should be like this one: https://i.stack.imgur.com/HYvaU.png.
I have only added the image as a background but I cannot find any solution for this oppacity.
My HTML:
<header>
<img src="images/logo.svg" />
<h1>A history of everything you copy</h1>
<p>
Clipboard allows you to track and organize everything you copy.
Instantly access your clipboard on all your devices.
</p>
</header>
And CSS:
body {
font-family: "Bai Jamjuree", sans-serif;
text-align: center;
}
#media (min-width: 1200px) {
header {
width: 100%;
background-image: url(images/bg-header-desktop.png);
background-size: 100%;
background-repeat: no-repeat;
padding-top: 50px 150px;
}
}
h1 {
color: hsl(210, 10%, 33%);
font-size: 35px;
margin-bottom: 15px;
}
header > p {
color: hsl(201, 11%, 66%);
font-size: 18px;
}
Thank you in advance!
I have tried to use mask-image but it didn't work:
#media (min-width: 1200px) {
header {
width: 100%;
background-image: url(images/bg-header-desktop.png);
mask-image: linear-gradient(180deg, rgba(0, 0, 0, 1), transparent 74%);
background-size: 100%;
background-repeat: no-repeat;
padding-top: 50px 150px;
}
}
Do you have maybe any idea if I can give an opacity only for the bottom part of this background image using CSS?
With more than 1 background, you can put image in 1 and opacity on the other.
You can change 2nd background color as you want. It's opacity value is given by the RGBA background color (here 0.75 in the snippet).
body {
margin: 0;
padding: 0;
}
.wrapper {
position: absolute;
width: 100vw;
height: 50vh;
top: 50%;
transform: translateY(-50%);
font-size: 10em;
font-weight: bold;
font-family: sans-serif;
background: url("https://picsum.photos/id/22/1280/600");
}
.wrapper1 {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
clip-path: inset(50% 0 0 0);
background-color: rgba(255, 255, 255, 0.75);
display: flex;
justify-content: center;
align-items: center;
}
.wrapper2 {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: 2;
}
<div class="wrapper">
<div class="wrapper1"></div>
<div class="wrapper2">Hello World!</div>
</div>
Look at the snipper in full scree, for this demo I put width 100vw, so in small result is "strange"

Dynamic height button with gradient and pointed end

I would like to create buttons with gradient as the background and a pointed end that will adjust to the height of the button, which depends on the amount of text inside. Page background can vary, so I can't use solid color for pointed end. The best solution I came up with is using after pseudo-element with svg code as a background-image, setting the background height to 100%, but this solution does not satisfy me too much, because I don't know if it will look good on all modern browsers. Do you have any ideas? Maybe I should use Javascript?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Button example</title>
<style>
html, body {
height: 100%;
}
body {
background-color: #e5e5e5;
}
.wrapper {
background-color: #ffffff;
padding: 15px;
max-width: 180px;
margin: 0 auto;
}
.btn {
position: relative;
display: inline-block;
background: #000000 linear-gradient(to bottom, #000000, #666666);
color: #ffffff;
font-family: Arial, Helvetica, sans-serif;
font-weight: bold;
padding: 8px 20px;
margin-right: 12px;
margin-bottom: 15px;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.btn::after {
content: '';
position: absolute;
top: 0px;
right: -12px;
display: inline-block;
height: 100%;
width: 13px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='13' height='40'%3E%3ClinearGradient id='css-btn-example' gradientUnits='userSpaceOnUse' x1='6.5' y1='40' x2='6.5'%3E%3Cstop offset='0' stop-color='%23666'/%3E%3Cstop offset='1'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23css-btn-example)' d='M0 0h1l12 20L1 40H0z'/%3E%3C/svg%3E");
background-size: 13px 100%;
}
.btn:last-child {
margin-bottom: 0;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="btn">One line</div>
<div class="btn">Two line button example</div>
<div class="btn">Three line button long example</div>
</div>
</body>
</html>
In case the gradient will always be from top to bottom (or bottom to top), you can consider some trick using skew like below. The idea is to use the pseudo elements where you apply two different gradient that will intersect at the same color creating the illusion of one gradient.
.box {
width: 150px;
padding: 20px;
box-sizing: border-box;
position: relative;
color: #fff;
z-index: 0;
overflow: hidden;
margin:5px;
border-radius:5px 0 0 5px;
}
.box:before,
.box:after {
content: "";
position: absolute;
z-index:-1;
height: 50%;
left: 0;
right: 0;
}
.box:before {
top: 0;
background: linear-gradient(to bottom, blue, #4100bf);
transform: skewX(30deg);
transform-origin: bottom right;
}
.box:after {
bottom: 0;
background: linear-gradient(to top, purple, #4100bf);
transform: skewX(-30deg);
transform-origin: top right;
}
<div class="box">
Some text here
</div>
<div class="box">
Some text here Some text here
</div>
Another idea without transparency is to consider mutilple background and hide the gradient with a white color (or any color of the background). You can then consider any kind of gradient, even a radial-gradient.
.box {
width: 150px;
padding: 20px;
box-sizing: border-box;
color: #fff;
margin:5px;
background:
linear-gradient(to bottom right,transparent 48%,#fff 50%) bottom right/20px 50%,
linear-gradient(to top right,transparent 48%,#fff 50%) top right/20px 50%,
linear-gradient(to bottom, blue,purple);
background-repeat:no-repeat;
border-radius:5px 0 0 5px;
}
<div class="box">
Some text here
</div>
<div class="box">
Some text here Some text here
</div>
You have also the clip-path solution:
.box {
width: 150px;
padding: 20px;
box-sizing: border-box;
color: #fff;
margin: 5px;
background: linear-gradient(to bottom, blue, purple);
background-repeat: no-repeat;
border-radius: 5px 0 0 5px;
-webkit-clip-path: polygon(0% 0%, calc(100% - 20px) 0%, 100% 50%, calc(100% - 20px) 100%, 0% 100%);
clip-path: polygon(0% 0%, calc(100% - 20px) 0%, 100% 50%, calc(100% - 20px) 100%, 0% 100%);
}
<div class="box">
Some text here
</div>
<div class="box">
Some text here Some text here
</div>

Why does align: center in the parent mess up my position: absolute overlays?

Could somebody explain why using display: flex; align: center; in the parent of this menu messes up the two absolutely positioned overlays in a child element?
Here's a fiddle where you can try it with and without align: center to get my meaning. (uncomment /* align: center; */ in .menu)
https://jsfiddle.net/Hastig/wmtr87gc/
body { background-color: gray;}
.menu {
display: flex;
justify-content: center;
/* align-items: center; */
width: 100%;
padding: 5px 0;
background-color: hsl(0, 0%, 30%);
}
.menu-item {
position: relative;
display: flex;
justify-content: center;
align-items: center;
flex: 1;
font-size: 13px;
color: hsl(0, 0%, 70%);
}
.menu-item.progress {
background-color: gray;
}
.progress-bar {
position: absolute;
top: 0; bottom: 0; left: 0;
width: 83%;
background-color: hsla(191, 58%, 46%, 1);
}
.progress-value {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
color: hsl(0, 0%, 90%);
}
<div class="menu">
<div class="menu-item">Stuff</div>
<div class="menu-item progress">
<div class="progress-bar"></div>
<div class="progress-value">83</div>
</div>
<div class="menu-item">Things</div>
</div>
Because the middle element contains only absolute elements so there is no in-flow content inside it to define its height. Then the default align-items is stretch so your element will get stretched by default and its height will be equal to its parent height BUT if you change the alignment the element will consider its content to define the height and since there no in-flow element it will have height:0 which means that the progress bar defined by top:0;bottom:0 will also have height 0.
To avoid this, keep at least one of the element not positoned (the one that contain the text) so that the middle element have some in-flow content and its height will be different from 0 whataver the alignment will be.
body {
background-color: gray;
}
.menu {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
padding: 5px 0;
background-color: hsl(0, 0%, 30%);
}
.menu-item {
position: relative;
z-index:0;
display: flex;
justify-content: center;
align-items: center;
flex: 1;
font-size: 13px;
color: hsl(0, 0%, 70%);
}
.menu-item.progress {
background-color: gray;
}
.progress-bar {
position: absolute;
z-index:-1;
top: 0;
bottom: 0;
left: 0;
width: 83%;
background-color: hsla(191, 58%, 46%, 1);
}
.progress-value {
color: hsl(0, 0%, 90%);
}
<div class="menu">
<div class="menu-item">Stuff</div>
<div class="menu-item progress">
<div class="progress-bar"></div>
<div class="progress-value">83</div>
</div>
<div class="menu-item">Things</div>
</div>

How to make a triangle hover effect behind menu option

I'm trying to add a hover effect for a menu -
It should be pretty simple but I haven't found any scss or css work arounds yet... Below is an image that shows specifically what I'm talking about.
A simple linear-gradient will do it:
.container {
background:grey;
padding:10px;
}
.nav {
display: inline-block;
padding: 10px;
color: #fff;
}
.nav:hover {
background: linear-gradient(to bottom right, transparent 50%, red 51%);
}
<div class="container">
<div class="nav">TEXT</div>
<div class="nav">long TEXT</div>
<div class="nav">A</div>
<div class="nav">BBBBBBBBBBB</div>
</div>
You can use clip-path to shape the triangle, although browser support Eh.
button {
background: #112b1bb8;
border: 1px solid black;
padding: 10px 40px;
position: relative;
}
button:hover:before {
content: '';
width: 100%;
height: 100%;
background: grey;
position: absolute;
top: 0;
left: 0;
z-index: -1;
clip-path: polygon(0% 100%, 100% 0%, 100% 100%);
}
<button>Brand</button>
<button>Link Link</button>
<button>O</button>

Any way to declare a size/partial border to a box?

Any way to declare a size/partial border to a box in CSS? For example a box with 350px that only shows a border-bottom in its firsts 60px. I think that might be very useful.
Examples:
Not really. But it's very easy to achieve the effect in a way that degrades gracefully and requires no superfluous markup:
div {
width: 350px;
height: 100px;
background: lightgray;
position: relative;
margin: 20px;
}
div:after {
content: '';
width: 60px;
height: 4px;
background: gray;
position: absolute;
bottom: -4px;
}
<div></div>
I know, this is already solved and pixels were requested. However, I just wanted to share something...
Partly underlined text elements can easily achieved by using display:table or display:inline-block
(I just don't use display:inline-block because, yeah you know, the awkward 4px-gap).
Textual Elements
h1 {
border-bottom: 1px solid #f00;
display: table;
}
<h1>Foo is not equal to bar</h1>
Centering, display:table makes it impossible to center the element with text-align:center.
Let's work around with margin:auto...
h1 {
border-bottom: 1px solid #f00;
display: table;
margin-left: auto;
margin-right: auto;
}
<h1>Foo is not equal to bar</h1>
Well, that's nice, but it's not partially.
As bookcasey already introduced, pseudo-elements are worth gold.
h1 {
display: table;
margin-left: auto;
margin-right: auto;
}
h1:after {
border-bottom: 1px solid #f00;
content: '';
display: block;
width: 50%;
}
<h1>Foo is not equal to bar</h1>
Offset, the underline is left aligned right now. To center it, just push the pseudo-element the half of its width (50% / 2 = 25%) to the right.
h1 {
display: table;
margin-left: auto;
margin-right: auto;
}
h1:after {
border-bottom: 1px solid #f00;
content: '';
display: block;
margin-left: 25%;
width: 50%;
}
<h1>Foo is not equal to bar</h1>
...as davidmatas commented, using margin:auto is sometimes more practical, than calculating the margin-offset by hand.
So, we can align the underline to the left, right or center (without knowing the current width) by using one of these combinations:
Left: margin-right: auto (or just leave it off)
Middle: margin: auto
Right: margin-left: auto
Full example
.underline {
display: table;
margin-left: auto;
margin-right: auto;
}
.underline:after {
border-bottom: 1px solid #f00;
content: '';
display: block;
width: 50%;
}
.underline--left:after {
margin-right: auto; /* ...or just leave it off */
}
.underline--center:after {
margin-left: auto;
margin-right: auto;
}
.underline--right:after {
margin-left: auto
}
<h1 class="underline underline--left">Foo is not equal to bar</h1>
<h1 class="underline underline--center">Foo is not equal to bar</h1>
<h1 class="underline underline--right">Foo is not equal to bar</h1>
Block-Level Elements
This can easily be adopted, so that we can use block-level elements. The trick is to set the pseudo-elements height to the same height as its real element (simply height:100%):
div {
background-color: #eee;
display: table;
height: 100px;
width: 350px;
}
div:after {
border-bottom: 3px solid #666;
content: '';
display: block;
height: 100%;
width: 60px;
}
<div></div>
Here is another solution that rely on linear-gradient where you can easily create any kind of line you want. You can also have multiple lines (on each side for example) by using multiple background:
.box1 {
width: 200px;
padding: 20px;
margin: 10px auto;
text-align: center;
background:
linear-gradient(to right, transparent 20%, #000 20%, #000 40%, transparent 40%) 0 100% / 100% 3px no-repeat,
#ccc
}
.box2 {
width: 200px;
padding: 20px;
margin: 10px auto;
text-align: center;
background:
linear-gradient(to right, transparent 20%, red 20%, red 80%, transparent 80%) 0 100% / 100% 2px no-repeat,
#ccc
}
.box3{
width: 200px;
padding: 20px;
margin: 10px auto;
text-align: center;
background:
linear-gradient(to right, transparent 20%, red 20%, red 80%, transparent 80%) 0 100% / 100% 2px no-repeat,
linear-gradient(to right, transparent 30%, blue 30%, blue 70%, transparent 70%) 0 0 / 100% 2px no-repeat,
linear-gradient(to bottom, transparent 30%, brown 30%, brown 70%, transparent 70%) 0 0 / 3px 100% no-repeat,
linear-gradient(to bottom, transparent 20%, orange 20%, orange 70%, transparent 70%) 100% 0 / 3px 100% no-repeat,
#ccc
}
<div class="box1">
Box1
</div>
<div class="box2">
Box2
</div>
<div class="box3">
Box3
</div>
Here is another syntax to achieve the same as above:
.box1 {
width: 200px;
padding: 20px;
margin: 10px auto;
text-align: center;
background:
linear-gradient(#000 0 0) top /40% 3px no-repeat,
#ccc
}
.box2 {
width: 200px;
padding: 20px;
margin: 10px auto;
text-align: center;
background:
linear-gradient(red 0 0) bottom/ 60% 2px no-repeat,
#ccc;
}
.box3{
width: 200px;
padding: 20px;
margin: 10px auto;
text-align: center;
background:
linear-gradient(red 0 0)bottom left/ 60% 2px,
linear-gradient(blue 0 0) 60% 0 / 40% 2px,
linear-gradient(brown 0 0) left/ 3px 30%,
linear-gradient(orange 0 0) right / 3px 40%,
#ccc;
background-repeat:no-repeat;
}
<div class="box1">
Box1
</div>
<div class="box2">
Box2
</div>
<div class="box3">
Box3
</div>
I used a grid to build draw some of the borders.
See here.
Code:
/* ungrid without mobile */
.row {
width: 100%;
display: table;
table-layout: fixed;
}
.col {
display: table-cell;
}
/* things to change */
.row {
width: 70%;
margin: auto;
}
.mid.row>.col {
height: 150px;
}
/* draw box and align text */
.col {
text-align: center;
}
.top.left.col {
border-top: 1px solid black;
border-left: 1px solid black;
}
.top.right.col {
border-top: 1px solid black;
border-right: 1px solid black;
}
.bottom.left.col {
border-bottom: 1px solid black;
border-left: 1px solid black;
}
.bottom.right.col {
border-bottom: 1px solid black;
border-right: 1px solid black;
}
.mid.row>.col {
border-left: 1px solid black;
border-right: 1px solid black;
vertical-align: middle;
}
.top.center.col {
position: relative;
top: -0.5em;
}
.bottom.center.col {
position: relative;
bottom: -0.5em;
}
<div class="row">
<div class="top left col"></div>
<div class="top center col">Top</div>
<div class="top right col"></div>
</div>
<div class="mid row">
<div class="col">Mid</div>
</div>
<div class="row">
<div class="bottom left col"></div>
<div class="bottom center col">Bottom</div>
<div class="bottom right col"></div>
</div>
CSS does not support partial borders. You'd need to use an adjacent element to simulate this.
Been playing a bit around with your solutions and came up with that.
I'd appreciate your comments and thoughts.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>test file</title>
<style>
#box {
background-color: gray;
position: relative;
left: 10px;
top: 10px;
height: 180px;
width: 380px;
}
#grad1 {
position: absolute;
left: -10px;
top: -10px;
height: 40px;
width: 2px;
background-image: linear-gradient(red, red);
}
#grad2 {
position: absolute;
left: -10px;
top: -10px;
height: 2px;
width: 40px;
background-image: linear-gradient(red, red);
}
</style>
</head>
<body>
<div id="box">
<div id="grad1"></div>
<div id="grad2"></div>
</div>
</body>
</html>

Resources