React Application: How To Create A Black Overlay For A Picture? - css

I'm trying to create a black overlay for a picture featured in the header of my application, using ReactJS and CSS3. However, no matter what I do, it's not working. I've tried referencing old projects in the past, where I managed to pull it off, as well as explored StackOverflow for answers. But, nothing's worked.
Could somebody please help me understand what I'm doing wrong and how I can solve this? I'd really appreciate it.
Header.js
import React from 'react';
// import { Link } from 'react-router-dom';
import Button from 'react-bootstrap/Button';
import ButtonToolBar from 'react-bootstrap/ButtonToolbar';
import './header.css';
const Header = () => {
return (
<div className="header">
<h1 className="title">Linguist Otaku</h1>
<ButtonToolBar>
<Button href="/quiz" size="lg" id="quiz-btn">
Quiz Now
</Button>
</ButtonToolBar>
</div>
)
}
export default Header;
Header.css
:root{
--mainOpacity: rgb(0, 0, 0, .55);
}
.header {
background-image: url("../../images/italy.png");
opacity: var(--mainOpacity);
height: 30em !important;
}
h1 {
font-family: "Fjalla One";
text-align: center !important;
padding-top: 2em !important;
color: white !important;
font-size: 4em !important;
}
.btn-toolbar {
display: flex !important;
justify-content: center !important;
}
#quiz-btn {
font-family: "Roboto";
color: white !important;
margin-top: 3em !important;
background-color: transparent !important;
border: solid .05em white !important;
border-radius: 0em !important;
}
#quiz-btn:hover {
transition: all 0.5s ease-in-out;
background-color: var(--mainOpacity) !important;
}

To create an overlay, you should wrap the content in another div. Then with CSS, position it right in-front of the header/background like so: https://codesandbox.io/s/mystifying-ramanujan-sq491
Header.js
const Header = () => {
return (
<div className="header">
<div className="dark-overlay">
<h1 className="title">Linguist Otaku</h1>
<ButtonToolBar>
<Button href="/quiz" size="lg" id="quiz-btn">
Quiz Now
</Button>
</ButtonToolBar>
</div>
</div>
);
};
CSS
.dark-overlay {
background-color: rgba(0, 0, 0, 0.35);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}

You can give a background image and black overlay together in the css to the "header" or your parent like this:
background-image: linear-gradient( rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7) ),url("../../images/italy.png");

Related

CSS hover animation works codesandbox (React), but breaks when implemented in Next.js project

Problem
In codesandbox I built a hover animation for a div-element. I used the working code on a li-element in my next.js project, but after copying over the code the hover-effect isn't triggered on hover, but on click instead. Plus: The element stays stuck in the hovering position, until the next click is exerted. Weird?
Recorded a little video --> https://www.youtube.com/watch?v=IV7PIvmpzX8
What could be the problem?
The relevant code for this page:
import Link from "next/link";
import styled from "styled-components";
console.clear();
const StyledUl = styled.ul`
display: grid;
grid-template-columns: 1fr;
gap: 30px;
padding: 0px 50px;
`;
const StyledLi = styled.li`
display: grid;
place-items: center;
height: 80px;
position: relative;
box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 3px, rgba(0, 0, 0, 0.24) 0px 1px 2px;
border-radius: 20px;
transition: all 0.1s ease-in-out;
&:hover {
transform: scale(1.1);
}
&:hover::after {
opacity: 1;
}
&::after {
content: "";
position: absolute;
width: 100%;
height: 100%;
box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
border-radius: 20px;
opacity: 0;
transition: opacity 0.1s ease-in-out;
}
`;
const StyledP = styled.p`
font-size: var(--fontsize_pageText);
`;
export default function Main() {
return (
<StyledUl>
<StyledLi>
<StyledP>something</StyledP>
</StyledLi>
<StyledLi>
<StyledP>something</StyledP>
</StyledLi>
<StyledLi>
<StyledP>something</StyledP>
</StyledLi>
<StyledLi>
<StyledP>something</StyledP>
</StyledLi>
</StyledUl>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
The behaviour is normal, when you are in tablet/mobile mode on every browser the browser switches from an usual cursor to an emulated touch cursor which replaces the usual desktop browser events with touch events.
In Chrome you can change that using their tools like it's shown in their docs

How to change CSS of a child component from parent component

I have a react component called TeamBanner like so
import styles from "./teamBanner.module.css";
import { useNavigate } from "react-router-dom";
import { TeamBannerProps } from "../ProjectTypes.types";
export const TeamBanner = ({
team,
onBannerClick,
showName,
}: TeamBannerProps) => {
let navigate = useNavigate();
const handleOnClick = () => {
navigate(`/${team}`);
onBannerClick();
};
return (
<div
className={`${styles.container} flex theme-light ${
showName ? "" : styles["no-name"]
}`}
title={team}
onClick={handleOnClick}
>
<div>
<img
src={require(`../logos/${team}.svg`)}
alt="logo"
className={`${styles.logo} ${showName ? "" : styles["only-logo"]}`}
/>
</div>
{showName ? team : ""}
</div>
);
};
The teamBanner.module.css file is like so
.container {
margin: 0.25em;
align-items: center;
cursor: pointer;
top: 0;
z-index: 2;
background-color: hsl(var(--color-background));
padding: 0.1em 0.25em;
border-radius: 0.5em;
box-shadow: 0.05rem 0.05rem 0.2rem rgb(0 0 0 / 50%);
font-family: var(--ff-serif);
font-size: var(--fs-200);
}
.logo {
display: inline-block;
vertical-align: middle;
width: 3vmax;
height: 3vmax;
}
.container:hover {
outline: 0.15em solid hsl(240, 90%, 67%);
}
.no-name {
border-radius: 0.25em;
}
.only-logo {
width: 5vmax;
height: 5vmax;
}
I am using it to create a list of team of a page & this works just fine.
However, I want to use it in another place also. In the place, the to now want the .container:hover effect & I want the font properties of the .contaner and width & height properties of the .logo changed.
How can I accomplish this? only changing these items of the module.css? Can any one help? Thanks

How to change a slide out drawer in react grid to position fixed

I am trying to create a slide out drawer exactly like the one present in JIRA.
Here is what JIRA looks like (notice how sidebar opens and pushes content to the side):
Here is what I have managed to create in my code:
The sliding effect and shelf looks similar enough and I am happy with it. However, there is one feature that Jira has that I find quite interesting and would like to recreate in my code base. When the sidebar is closed, and the user hovers over the sliver of sidebar that remains, the sidebar opens up as if the button to open had been clicked, and it then closes when the mouse leaves the sidebar. What is really interesting to me is that the grid format does not change and the sidebar appears to not move the other content on the page which makes me believe it somehow switches to a fixed position just during this mouse over event. I am not sure how to achieve this effect and my code is currently not working. Any help would be greatly appreciated!
Here is the desired effect (notice how sidebar opens and DOES NOT push content to the side, which is different than actually clicking the button. See first gif example):
EDIT: Here is the effect for mousing in to the sidebar and the button becoming visible while in the sidebar:
Here is what I have tried so far:
(SideBar Component)
import React, { useState, useRef } from 'react';
import { Link } from 'react-router-dom';
import './RenewalSidebar.css';
function RenewalSidebar({ worksheetID }) {
const [sidebar, setSidebar] = useState(false);
const [cursorInSidebar, setCursorInSidebar] = useState(false);
const showSidebar = () => setSidebar(!sidebar);
const sidebarRef = useRef(null);
return (
<nav
ref={sidebarRef}
className={sidebar ? 'sidebar' : 'sidebar inactive'}
onMouseLeave={() => setCursorInSidebar(false)}
onMouseOver={(e) => {
if (e.target === sidebarRef.current || sidebarRef.current.contains(e.target)) {
console.log(`Hey I'm in the sidebar`);
setCursorInSidebar(true);
}
}}
data-sidebarhover={cursorInSidebar}
data-sidebaropen={!sidebar}
>
<div
role="button"
tabIndex={0}
className="hamburger"
type="button"
onClick={showSidebar}
data-open={!sidebar}
data-hover={cursorInSidebar}
onMouseEnter={() => setCursorInSidebar(true)}
onMouseLeave={() => setCursorInSidebar(false)}
>
{sidebar ? '>' : '<'}
</div>
<div className="sidebar-content">
<ul onClick={showSidebar} data-open={!sidebar}>
<li>
<Link to={`/`}>Test</Link>
</li>
<li>
<Link to={`/`}>Test</Link>
</li>
<li>
<Link to={`/`}>Test</Link>
</li>
</ul>
</div>
</nav>
);
}
export default RenewalSidebar;
Here is my css for the top level grid container I am using:
.RenewalsDetailContainer {
display: grid;
grid-template-columns: max-content 1fr;
justify-items: center;
}
And here is my css for the Sidebar component:
.sidebar {
position: relative;
/* top: 20vh;
left: -300px; */
width: 20px;
height: 100%;
/* border-radius: 0px 5px 5px 0px; */
background-color: aliceblue;
z-index: 0;
transition: width 200ms ease-out;
box-shadow: inset -10px 0 25px -25px #888;
padding: 0 10px;
}
.sidebar.inactive {
width: 300px;
z-index: 6000;
}
.sidebar ul {
margin: 0;
padding: 0;
}
.sidebar ul[data-open='false'] {
display: none;
}
.sidebar li a {
display: block;
border: none;
background-color: white;
padding: 14px 28px;
font-size: 16px;
margin: 10px 10px 10px 10px;
width: auto;
text-align: center;
}
/* .sidebar[data-sidebaropen='false'][data-sidebarhover='true'] {
z-index: -9000;
} */
.sidebar[data-sidebaropen='false'][data-sidebarhover='true'] .sidebar-content {
position: fixed;
width: 300px;
top: 0;
left: 0;
background-color: purple;
}
.hamburger {
color: rgb(107, 119, 140);
background-color: rgb(255, 255, 255);
height: 24px;
border: none;
outline: 0;
width: 24px;
top: 32px;
position: absolute;
right: 0px;
font-size: 15px;
font-weight: bold;
border-radius: 50%;
transform: translateX(50%);
display: grid;
place-items: center;
transition: all 500ms linear, color 100ms linear, opacity 350ms cubic-bezier(0.2, 0, 0, 1);
box-shadow: rgb(9 30 66 / 8%) 0px 0px 0px 1px, rgb(9 30 66 / 8%) 0px 2px 4px 1px;
}
.hamburger:hover {
background-color: #4c9aff;
color: white;
box-shadow: none;
cursor: pointer;
}
.hamburger[data-open='true'] {
opacity: 0;
}
.hamburger[data-open='true']:hover {
opacity: 1;
}
.hamburger[data-open='true'][data-hover='true'] {
opacity: 1;
}
.hamburger:after,
.hamburger:before,
.hamburger div {
background-color: #0076c7;
/* margin: 7px 0; */
border-radius: 3px;
content: '';
display: block;
transition: all 300ms ease-in-out;
}
.sidebar-content {
position: relative;
width: 100%;
height: 100%;
}
.sidebar-content .sidebar.active .hamburger div {
transform: scale(0);
}
And finally...here is a Code sandbox link I have created to help you test the code. Click me!
I believe I have addressed all of your feature requests in this updated CodeSandbox:
https://codesandbox.io/s/jira-inspired-menu-bnyd8
The crux of the solution was to decouple the SideBar content from the mechanics of how that column is propped open, depending on UI state. It required a bit of nesting and absolute positioning to get the job done.
The content width of the SideBar is measured with getBoundingClientRect() when the panel is opened up, and then that value is stored in state. That value is then used to control the width of the SideBar container when it is open, as well as the shim width (which is what actually pushes the main content to the side when the SideBar is fully opened) and hamburger x coordinate.
Relevant code for my solution is in SideBar.js and SideBar.css in the CodeSandbox link above.
Preview of UI in action:
I have made few changes to accommodate this.
Nesting of sidebar and button will raise conflict between onMouseEnter events, you won't be able to click on the button. (Moved the button outside nav)
Position absolute does not push the content. And you can use react inline styles like this :
style={{position: cursorInSidebar && !sidebar ? "absolute" : "relative"}}
Added isOpen to track if the sidebar is open. Either by button click or mouse hover.
onClick events should set cursorInSidebar.
const SideBar = () => {
const [sidebar, setSidebar] = useState(false);
const [cursorInSidebar, setCursorInSidebar] = useState(false);
const showSidebar = (isOpen) => {
setSidebar(!isOpen);
setCursorInSidebar(false);
};
const sidebarRef = useRef(null);
const enterSideBar = () => {
setCursorInSidebar(true);
};
const leaveSideBar = () => {
setCursorInSidebar(false);
};
const isOpen = sidebar || cursorInSidebar;
return (
<div className="divSid">
<div
role="button"
tabIndex={0}
className="hamburger"
type="button"
onClick={() => showSidebar(isOpen)}
data-open={isOpen}
>
{isOpen ? "<" : ">"}
</div>
<nav
ref={sidebarRef}
style={{
position: cursorInSidebar && !sidebar ? "absolute" : "relative"
}}
className={isOpen ? "sidebar inactive" : "sidebar"}
data-sidebaropen={isOpen}
onMouseEnter={enterSideBar}
onMouseLeave={leaveSideBar}
>
<div className="sidebar-content">
<ul onClick={() => showSidebar(isOpen)} data-open={isOpen}>
<li>Test</li>
<li>Test</li>
<li>Test</li>
</ul>
</div>
</nav>
</div>
);
};
While moving button outside nav, alignment of components will break. Here is the working code.

I want to use a transition for the moment when two icons switch with each other

I'm a beginner, i searched a lot for an answer on the internet but none of them managed to clarify why the transition doesn't work.
HTML:
<li><i class="material-icons menu-bar" id="menu-bar">menu</i></li>
<ul class="menu-bar-content hide" id="menu-bar-content">
This is my Js :
const menuBar = document.getElementById('menu-bar');
const menuBarContent = document.getElementById('menu-bar-content');
var menuOpen = false;
menuBar.addEventListener('click' , menuBarBtn)
function menuBarBtn() {
if ( menuOpen == false) {
menuBar.innerHTML = '<li><i class="material-icons undo-icon">undo</i></li>';
menuBarContent.className = 'menu-bar-content';
menuOpen = true;
}
else {
menuBar.innerHTML = '<li><i class="material-icons menu-bar" id="menu-bar">menu</i></li>';
menuBarContent.className = 'menu-bar-content hide'
menuOpen = false;
}
};
And this is my Css:
.menu-bar {
display: inline-block;
vertical-align: middle;
float: right;
color: white;
margin: -1.45% 0.7%;
font-size: 23px !important;
transition: .4s;
}
.undo-icon {
display: inline-block;
vertical-align: middle;
float: right;
color: #1ec7b9;
margin: 0.9% 3%;
transform: rotateZ(43.2deg);
font-size: 14px !important;
border: 2px solid rgb(255, 255, 255);
border-radius: 70%;
padding: 1.5px;
transition: .4s;
}
After the icons switch with each other, i wanted to do it with a transition effect. Thank you in advance!
The transition is not happening because the element is completely removed/replaced with another onclick.
It is CSS properties that transition and the browser thinks it's got a completely new element, not one that is to be transitioned in some way.
What we do is have both li elements in the document all the time, but one of them will be hidden. To do this gradually we can use opacity: 0 alongside the rotation in a new class which is called faded here.
On a click we don't replace the li elements but we set the one that has not been clicked to have class faded - it will rotate and end up invisible with opacity: 0 and we remove the class faded from the other li element so it will rotate back to normal and with normal opacity.
Javascript has a handy function, toggle, for adding and removing a class so we don't have to remember which element is hidden and which is in view - having or not having class faded is enough.
Here is the snippet. Note, the body has been given a background-color just so we can see the white menu and the white border. Also I do not have access to whatever icons you are using so the i elements are replaced with spans just for this demo.
const menuBar = document.getElementById('menu-bar');
const undoBar = document.getElementById('undo-bar');
menuBar.addEventListener('click' , menuBarBtn);
undoBar.addEventListener('click' , menuBarBtn);
function menuBarBtn() {
menuBar.classList.toggle('faded');
undoBar.classList.toggle('faded');
};
body {
background-color: gray; /* just for this test so we can see the white menu */
}
.menu-bar {
display: inline-block;
vertical-align: middle;
float: right;
color: white;
margin: -1.45% 0.7%;
font-size: 23px !important;
transition: .4s;
}
.undo-icon {
display: inline-block;
vertical-align: middle;
float: right;
color: #1ec7b9;
margin: 0.9% 3%;
font-size: 14px !important;
border: 2px solid rgb(255, 255, 255);
border-radius: 70%;
padding: 1.5px;
transition: .4s;
}
.faded { /* added this so when an element has class="faded" it cannot be seen and it is rotated */
opacity: 0;
transform: rotateZ(43.2deg);
}
<ul class="menu-bar-content" id="menu-bar-content" style="margin-top:30px;"> <!-- added just for this tesmargin t so we could see the white menu word in the snippet -->
<li><span class="menu-bar" id="menu-bar">menu</span></li> <!-- remember to put back the <i icon calls in here in place of the spans -->
<li><span class="menu-bar undo-icon faded" id="undo-bar">undo</span></li> <!-- ...and we start this off as faded so it isn't seen to begin with -->
</ul>

Scoped style affecting other pages

I have two pages in my nuxt app and both pages should have different backgrounds. However one background is overriding the other
index.vue
<style scoped>
body {
background-color: #ffffff;
}
#banner {
background-image: url("~assets/img/newbg.png");
}
</style>
login.vue
<style >
body {
background-image: linear-gradient(
to right,
rgba(0, 0, 0, 0.9),
rgba(0, 0, 0, 0.4)
),
url("~assets/img/starter_image.jpg");
background-position: center;
background-size: cover;
position: relative;
}
</style>
The background of the login.vue overrides the index.vue. if a scope the style of login.vue the styling of the page changes.
It will definitely override the styles because you're not using scoped attribute which will allow it to override the styles of the parent component.
If you want to have another background in Login.vue
then this might help:
Inside Login.vue
HTML:
<div id="wrapper" v-bind:style="bgc">
*Write your html here*
</div>
CSS
#wrapper {
height: 100vh;
width: 100vw;
background-color: #111;
position: absolute;
left: 0;
top: 0;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
transition: 0.5s;
}
JS
new Vue({
el: '#wrapper',
data: {
bgc: {
backgroundColor: ''
}
}
})
index.vue
<style scoped>
body {
background-color: #ffffff;
}
#banner {
background-image: url("~assets/img/newbg.png");
}
</style>
login.vue
<style scoped>
body {
background-image: linear-gradient(
to right,
rgba(0, 0, 0, 0.9),
rgba(0, 0, 0, 0.4)
),
url("~assets/img/starter_image.jpg");
background-position: center;
background-size: cover;
position: relative;
}
</style>
you can use scoped for your component that will not affect to your other component.there are two different components (login, index).

Resources