Im stuck on a simple error, but just can't find it.
I have created an const, too style an element. Now I want to put the constant into the CSS, but somehow that doesn't work.
I want delete this line:
<div style={OVERLAY_STYLES}/>
Can somebody explain my mistake?
const OVERLAY_STYLES = {
position: "fixed",
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: "rgba(0,0,0, .7)",
zIndex: 1000,
};
export default function Modal({ open, children, onClick }) {
const [check, setCheck] = useState([]);
......
return ReactDOM.createPortal(
<div className="OVERLAY_STYLES">
<div style={OVERLAY_STYLES}/>
<div className="MODAL_STYLES">
<h1>Blabla.</h1>
{attribute.map((att, index) => {
return (
<div>
......
</div>
);
})}
<div className="b01">
<button onClick={() => onClick(check)} >Submit</button>
</div>
</div>
</div>
,
document.getElementById("portal")
);
}
.OVERLAY_STYLES {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0,0,0, .7);
z-index: 1000;
};
In react inline styling, all values need to be inside ' ' . Change your OVERLAY_STYLES code to:
.OVERLAY_STYLES {
position: 'fixed';
top: '0';
left: '0';
right: '0';
bottom: '0';
backgroundColor: 'rgba(0,0,0, .7)';
z-index: '1000';
};
also, no dashes so change background-color to backgroundColor
Root Cause:-
You are wrapping your <div style={OVERLAY_STYLES}/> under <div className="OVERLAY_STYLES">.
You are using the same style on both div tags which have z-index applied with the same value. So in your case:- with inline-style is appearing above the parent div by hiding it under itself.
I am attaching the snippet have a look for the reference:-
const OVERLAY_STYLES = {
position: "fixed",
top: 20,
left: 20,
right: 20,
bottom: 20,
backgroundColor: "red",
zIndex: 1000,
color:"white",
width:"50%",
};
const App = () => /*#__PURE__*/React.createElement("div", {
className: "OVERLAY_STYLES"
}, /*#__PURE__*/React.createElement("div", {
style: OVERLAY_STYLES
}, "hELLO"));
ReactDOM.render( /*#__PURE__*/React.createElement(App, null), document.getElementById("app"));
.OVERLAY_STYLES{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: ;
background-color: yellow;
z-index: 1000;
color:green;
width:100vw;
height:700px;
};
<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>
<div id="app"></div>
Solution:-
Try changing z-index/width.
Note:-Element with higher z-index will be at the top.
Related
I got inspired to create this animation effect. What I want to achieve is that the overlapped images get a little bigger when scrolling down and then again smaller when I scroll back.
For the scrolling part I know I need to use Intersection Observer API. I think I managed it to do right but I cant get it to work. I use React Typescript with inline styling.
The original animation - Three overlaping images - getting bigger on scroll down:
Codepen
My React Code - OverlappingImages.tsx :
import React from 'react';
const styles = {
container: {
position: 'relative',
height: '400px',
margin: '0 50px',
div: {
width: '380px',
border: '1px solid #000',
overflow: 'hidden',
lineHeight: 0,
transition: 'transform .4s ease-in-out',
img: {
width: '100%',
fontSize: 0,
},
},
img1: {
left: '5%',
top: 0,
position: 'absolute',
transform: 'rotate(-4deg) translateY(20%)',
transitionDelay: '0s',
},
img2: {
left: '50%',
top: 0,
position: 'absolute',
transform: 'translate(-50%, 0)',
transitionDelay: '.1s',
zIndex: 1,
},
img3: {
right: '5%',
top: 0,
position: 'absolute',
transform: 'rotate(4deg) translateY(20%)',
transitionDelay: '.2s',
},
' &.active': {
img1: {
transform: 'rotate(-6deg) translateY(50%) scale(1.9)',
},
img2: {
transform: 'translate(-50%, -2%) scale(1.2)',
},
img3: {
transform: 'rotate(6deg) translateY(24%) scale(1.2)',
},
},
},
body: {
fontFamily: 'sans-serif',
fontSize: '48px',
fontWeight: 'bold',
letterSpacing: '1px',
margin: 0,
},
section: {
textAlign: 'center',
padding: '500px 0',
'&:nth-child(odd)': {
background: '#eee',
},
},
};
function OverlappingImages() {
const wrapper = document.querySelector('.container');
const className = 'active';
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
wrapper.classList.add(className);
return;
}
wrapper.classList.remove(className);
});
},
{
threshold: 1,
}
);
observer.observe(wrapper);
return (
<>
<section>
<p>(scroll down!)</p>
</section>
<section>
<div style={styles.container}>
<div style={styles.container.img1}>
<img src="https://via.placeholder.com/350x250" alt="img1" />
</div>
<div style={styles.container.img2}>
<img src="https://via.placeholder.com/350x250" alt="img2" />
</div>
<div style={styles.container.img3}>
<img src="https://via.placeholder.com/350x250" alt="img3" />
</div>
</div>
</section>
<section>
<p>(scroll up!)</p>
</section>
</>
);
}
export { OverlappingImages };
Here's the result:
You need to wrap your code above reutrn(), into the window.onload because if you run it in the way your currently doing it, document.querySelector('.container') is going to return nothing but null or undefined
Your container has no class or id and your trying to access it with document.querySelector('.container') again you'll get null
Make sure you assign an id or a class to it
Style.css
#container * {
transition: all .5s ease;
}
.active div:nth-child(1) {
transform: rotate(-4deg) translateY(20%) scale(1.1) !important;
}
.active div:nth-child(2) {
transform: translate(-50%, 0%) scale(1.1) !important;
}
.active div:nth-child(3) {
transform: rotate(4deg) translateY(20%) scale(1.1) !important;
}
OverlappingImages.tsx
const styles = {
container: {
position: "relative",
height: "400px",
margin: "0 50px",
padding: "30px",
transition: "all .5s ease",
img1: {
left: "5%",
top: 0,
position: "absolute",
transform: "rotate(-4deg) translateY(20%)",
transitionDelay: "0s",
},
img2: {
left: "50%",
top: 0,
position: "absolute",
transform: "translate(-50%, 0)",
transitionDelay: ".1s",
zIndex: 1,
},
img3: {
right: "5%",
top: 0,
position: "absolute",
transform: "rotate(4deg) translateY(20%)",
transitionDelay: ".2s",
},
},
whiteSpace: {
display: "flex",
alignItems: "center",
justifyContent: "center",
height: "100vh",
},
};
function OverlappingImages() {
window.onload = function () {
const wrapper = document.querySelector("#container");
const className = "active";
let preY = 0, preR = 0;
const observer = new IntersectionObserver(
entries => {
entries.forEach(e => {
const currentY = e.boundingClientRect.y;
const currentR = e.intersectionRatio;
if (currentY < preY || e.isIntersecting) {
wrapper?.classList.add(className);
} else if (currentY > preY && currentR < preR) {
wrapper?.classList.remove(className);
}
preY = currentY;
preR = currentR;
});
},
{ threshold: 0.8 }
);
observer.observe(wrapper);
};
return (
<>
<section>
<div style={styles.whiteSpace}>
<p>(scroll down!)</p>
</div>
</section>
<section>
<div style={styles.container} id="container">
<div style={styles.container.img1}>
<img src="https://via.placeholder.com/350x250" alt="img1" />
</div>
<div style={styles.container.img2}>
<img src="https://via.placeholder.com/350x250" alt="img2" />
</div>
<div style={styles.container.img3}>
<img src="https://via.placeholder.com/350x250" alt="img3" />
</div>
</div>
</section>
<section>
<div style={styles.whiteSpace}>
<p>(scroll up!)</p>
</div>
</section>
</>
);
}
export default OverlappingImages;
Second approach(using ref)
Style.css
.active div:nth-child(1) {
transform: rotate(-4deg) translateY(20%) scale(1.1) !important;
}
.active div:nth-child(2) {
transform: translate(-50%, 0%) scale(1.1) !important;
}
.active div:nth-child(3) {
transform: rotate(4deg) translateY(20%) scale(1.1) !important;
}
OverlappingImages.tsx
import {useRef, useEffect} from 'react';
const styles = {
container: {
position: "relative",
height: "400px",
margin: "0 50px",
padding: "30px",
img1: {
left: "5%",
top: 0,
position: "absolute",
transform: "rotate(-4deg) translateY(20%)",
transition: "all .5s ease",
},
img2: {
left: "50%",
top: 0,
position: "absolute",
transform: "translate(-50%, 0)",
transition: "all .5s ease .1s",
zIndex: 1,
},
img3: {
right: "5%",
top: 0,
position: "absolute",
transform: "rotate(4deg) translateY(20%)",
transition: "all .5s ease .2s",
},
},
whiteSpace: {
display: "flex",
alignItems: "center",
justifyContent: "center",
height: "100vh",
},
};
function OverlappingImages() {
const ref = useRef(null);
useEffect(()=>{
const wrapper = ref.current;
const className = "active";
let preY = 0, preR = 0;
const observer = new IntersectionObserver(
entries => {
entries.forEach(e => {
const currentY = e.boundingClientRect.y;
const currentR = e.intersectionRatio;
if (currentY < preY || e.isIntersecting) {
wrapper?.classList.add(className);
} else if (currentY > preY && currentR < preR) {
wrapper?.classList.remove(className);
}
preY = currentY;
preR = currentR;
});
},
{ threshold: 0.8 }
);
observer.observe(wrapper);
},[])
return (
<>
<section>
<div style={styles.whiteSpace}>
<p>(scroll down!)</p>
</div>
</section>
<section>
<div ref={ref} style={styles.container}>
<div style={styles.container.img1}>
<img src="https://via.placeholder.com/350x250" alt="img1" />
</div>
<div style={styles.container.img2}>
<img src="https://via.placeholder.com/350x250" alt="img2" />
</div>
<div style={styles.container.img3}>
<img src="https://via.placeholder.com/350x250" alt="img3" />
</div>
</div>
</section>
<section>
<div style={styles.whiteSpace}>
<p>(scroll up!)</p>
</div>
</section>
</>
);
}
export default OverlappingImages;
The styled-components approach:
I created dummy data for the loop.
Created simple components for section, figure and img. I used figure as a wrapper.
Replaced all necessary style from img to figure and changed styled logic from position: absolute to grid solution. It will allow us to keep the images in the center of the screen if screen size is large and make it flexible for the small screens.
The PictureWrapper (figure) can pass 2 props, position and state.
OverlappingImages.tsx
import { useRef, useEffect, useState, useMemo } from "react";
import styled, { css } from "styled-components";
import data from "./data";
export type TypePosition = "left" | "center" | "right";
interface IProps {
position: TypePosition;
active: boolean;
}
const Image = styled.img`
width: 100%;
height: auto;
`;
// Left image wrapper style with active, inactive state
const left = (active: boolean) => css`
${!active && css`transform: rotate(-4deg) translateX(calc(-1 * clamp(25%, 20vw, 75%)));`}
${active && css`transform: rotate(-6deg) translateX(calc(-1 * clamp(25%, 20vw, 75%))) scale(1.2);`}
transition-delay: 0s;
z-index: 1;
`;
// Center image wrapper style with active, inactive state
const center = (active: boolean) => css`
${active && css`transform: scale(1.2);`}
transition-delay: 0.1s;
z-index: 2;
`;
// Right image wrapper style with active, inactive state
const right = (active: boolean) => css`
${!active && css`transform: rotate(4deg) translateX(clamp(25%, 20vw, 75%));`}
${active && css`transform: rotate(6deg) translateX(clamp(25%, 20vw, 75%)) scale(1.2);`}
transition-delay: 0.2s;
z-index: 1;
`;
// Image wrapper component with 2 props:
// position: left | center | right
// active: true / false
const PictureWrapper = styled.figure<IProps>`
grid-column: 1;
grid-row: 1;
width: clamp(200px, 40vw, 380px);
display: flex;
border: 1px solid #000;
transition: transform 0.4s ease-in-out;
${({ position, active }) => position === "left" && left(active)}
${({ position, active }) => position === "center" && center(active)}
${({ position, active }) => position === "right" && right(active)}
`;
const Container = styled.section`
display: grid;
place-content: center;
position: relative;
margin: 0 50px;
`;
export const OverlappingImages = () => {
const [active, setActive] = useState(false);
const ref = useRef<HTMLElement>(null);
const callback = (entries: IntersectionObserverEntry[]) => {
const [entry] = entries;
if (entry.isIntersecting) {
setActive(entry.isIntersecting);
return;
}
setActive(false);
};
const options = useMemo(() => ({
root: null,
rootMargin: "0px",
threshold: 0.75
}), []);
useEffect(() => {
const container = ref.current;
// Observer with external callback function and options
const observer = new IntersectionObserver(callback, options);
if (container) observer.observe(container);
//cleanup when a component unmounted
return () => {
if (container) observer.unobserve(container);
};
}, [ref, options]);
const images = data.map((img) => {
return (
<PictureWrapper key={img.id} position={img.position} active={active}>
<Image src={img.image} />
</PictureWrapper>
);
});
return <Container ref={ref}>{images}</Container>;
};
data.ts
import { TypePosition } from "./OverlappingImages";
interface IData {
id: string;
image: string;
position: TypePosition;
}
export const data: IData[] = [
{
id: "d4a54w5s1d2sd24",
image: "https://via.placeholder.com/350x250",
position: "left"
},
{
id: "ad4e5qe4545d7ew4",
image: "https://via.placeholder.com/350x250",
position: "center"
},
{
id: "das54w5e1sa2dw5e5",
image: "https://via.placeholder.com/350x250",
position: "right"
}
];
export default data;
App.tsx
import "./styles.css";
import { OverlappingImages } from "./OverlappingImages";
export default function App() {
return (
<div className="App">
<section>
<p>(scroll down!)</p>
</section>
<OverlappingImages />
<section>
<p>(scroll up!)</p>
</section>
</div>
);
}
sections style
section {
display: grid;
place-content: center;
min-height: 100vh;
text-align: center;
}
section:nth-child(odd) {
background: #eee;
}
How can I get the position of a component without using GetElementById or getBoundingClientRect?
I'm using react/JSX to render components one inside of each other, and I'm trying to get the distance between the top of the parent and the bottom of the child, if I use that functions I need to wait until the child is rendered and I need to do the calculations on the parent
here is a sample code of what I'm doing
export function TestPage() {
return <BaseObject />;
}
function BaseObject() {
return (
<div
className="popBox"
style={{ top: "100px", left: "100px", width: "500px", height: "500px" }}
>
<div
className="popBox2"
style={{ top: "150px", left: "150px", width: "200px", height: "200px" }}
></div>
</div>
);
}
and the css
.popBox
{
background-color: #4F8989;
position: sticky;
}
.popBox2
{
background-color: #89694f;
position: sticky;
}
Here's an example of using the useLayoutEffect and useRef hooks to grab refs to the real DOM elements and querying their measurements.
function BaseObject() {
const ref1 = React.useRef();
const ref2 = React.useRef();
const [dump, setDump] = React.useState("");
React.useLayoutEffect(() => {
const el1 = ref1.current;
const el2 = ref2.current;
if(!(el1 && el2)) return;
setDump(
`${JSON.stringify(el1.getBoundingClientRect())}\n${JSON.stringify(el2.getBoundingClientRect())}`
);
});
return (
<React.Fragment>
{dump}
<div
className="popBox"
ref={ref1}
style={{
top: "100px",
left: "100px",
width: "500px",
height: "500px",
}}
>
<div
className="popBox2"
ref={ref2}
style={{
top: "150px",
left: "150px",
width: "200px",
height: "200px",
}}
></div>
</div>
</React.Fragment>
);
}
ReactDOM.render(<BaseObject />, document.getElementById("root"));
.popBox {
background-color: #4F8989;
position: sticky;
}
.popBox2 {
background-color: #89694f;
position: sticky;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>
<div id="root" />
I was going to the react router code here: modal-gallery
and came across this syntax
const Modal = ({ match, history }) => {
const image = IMAGES[parseInt(match.params.id, 10)]
if (!image) {
return null
}
const back = (e) => {
e.stopPropagation()
history.goBack()
}
return (
<div
onClick={back}
style={{
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
background: 'rgba(0, 0, 0, 0.15)'
}}
>
<div className='modal' style={{
position: 'absolute',
background: '#fff',
top: 25,
left: '10%',
right: '10%',
padding: 15,
border: '2px solid #444'
}}>
<h1>{image.title}</h1>
<Image color={image.color} />
<button type='button' onClick={back}>
Close
</button>
</div>
</div>
)
}
My Question is, what type of syntax is this? and how would you convert this into ES6 React.Component class
it is a React Stateless Functional Component (React SFC). It's a function, instead of a class.
Basically you don't need/have to convert it to a React.Component class as it's a valid way to declare a React.Component.
A SFC is normally referred to as a dumb component, as it only care about the props passed to it but nothing else. It's a component that is pure (it is not supposed to have any internal state) nor should have any side effects come out from its lifecycle functions.
React recommends that if you don't need internal state, nor lifecycle methods with your component, you should write it as a SFC.
You can have a further look here:
https://reactjs.org/docs/components-and-props.html
This is a pure function. You can look at it as just the render function of a React.Component.
Converting it then becomes easy, just paste the code inside you render function:
class Modal extends React.Component {
render() {
const { match, history } = this.props; // Here you get your props
const image = IMAGES[parseInt(match.params.id, 10)]
if (!image) {
return null
}
const back = (e) => {
e.stopPropagation()
history.goBack()
}
return (
<div
onClick={back}
style={{
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
background: 'rgba(0, 0, 0, 0.15)'
}}
>
<div className='modal' style={{
position: 'absolute',
background: '#fff',
top: 25,
left: '10%',
right: '10%',
padding: 15,
border: '2px solid #444'
}}>
<h1>{image.title}</h1>
<Image color={image.color} />
<button type='button' onClick={back}>
Close
</button>
</div>
</div>
)
}
}
I am trying to make a small jQuery plugin that is able to create an overlay to create a tinting effect. To create this overlay is simple enough using plain js & jQuery, but when I try to wrap it all up into a jQuery plugin I get the error message that append (and appendTo) are not functions. The plugin works if I use extend instead of append, but the it is simply changing the existing css code, while I want to create an actual overlay over any div or object.
(function ($) {
$.fn.tint = function( options )
{
var overlay = $.append(
{
backgroundColor: "black",
opacity: 0.5,
width: "100%",
height: "100%",
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
//"z-index": 1000,
}, options
);
return this.css(
{
backgroundColor: overlay.backgroundColor,
opacity: overlay.opacity,
width: overlay.width,
height: overlay.height,
position: overlay.position,
top: overlay.top,
left: overlay.left,
right: overlay.right,
bottom: overlay.bottom,
//z-index: overlay.z-index,
}
);
}
} ( jQuery ));
I guess you are trying to do $.extend (not $.append):
(function ($) {
$.fn.tint = function( options )
{
if($(this).find(".overlay").length > 0) return $(this);
var overlay = $.extend({
backgroundColor: "black",
opacity: 0.5,
width: "100%",
height: "100%",
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
//"z-index": 1000,
}, options);
$("<div class='overlay'>").css(
{
backgroundColor: overlay.backgroundColor,
opacity: overlay.opacity,
width: overlay.width,
height: overlay.height,
position: overlay.position,
top: overlay.top,
left: overlay.left,
right: overlay.right,
bottom: overlay.bottom,
//z-index: overlay.z-index,
}
).appendTo(this);
return $(this);
}
} ( jQuery ));
$(".overlay-target").on("click", function(){
$(this).tint({backgroundColor: "green"});
});
.overlay-target {
border: 1px solid red;
margin: 20px;
padding: 50px;
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='overlay-target'>I want an overlay</div>
I have a website, where I want to change between images in the background very smoothly. This is my actual javaScript-code for it:
var bg=[
'images/best.jpg',
'images/61182.jpg',
'images/bg.jpg'
];
$('._container-1').css('background-image','url('+bg[2]+')');
window.setInterval(
function(){
img=bg.shift();bg.push(img);
document.getElementsByClassName('_container-1')[0].style.backgroundImage='url('+img+')';
},
10000
);
Now, I want to change the images very slowly. I have tried a lot with jQuery-fadeIn/fadeOut-methods like this:
window.setInterval(
function(){
img=bg.shift();
bg.push(img);
$('._container-1').fadeOut(600, function() {
$('._container-1').css('background-image','url('+img+')');
$('._container-1').fadeIn(600);
});
},
17000
);
The problem is, that there are buttons and text in the container and they changes with the images. I want that the text and buttons are in the front all the time, only the background should fadeIn/fadeOut. My english is not perfect, I hope you understand my problem.
Can somebody help me please?
nina_berlini
I have uses 2 elements as background to achieve the effect. Also check demo on https://jsfiddle.net/n380u3cy/1/
HTML:
<div class="container">
<div class="background"></div>
<div class="background"></div>
<button>
Test button
</button>
</div>
CSS:
.container { position: relative; line-height: 100px; }
.container > .background,
.container > .background { position: absolute; top: 0; right: 0; bottom: 0; left: 0; background-size: contain; z-index: 0; }
.container > *:not(.background) { position: relative; z-index: 1; }
Javascript:
var bg=[
'images/best.jpg',
'images/61182.jpg',
'images/bg.jpg'
];
var Transition = 1000;
$('.background').css('background-image','url('+bg[bg.length - 1]+')');
window.setInterval(
function() {
img=bg.shift();
bg.push(img);
var $Backgrounds = $('.background');
$Backgrounds.eq(1).hide(0).css({
'background-image': 'url('+img+')'
}).fadeIn(Transition * .9);
$Backgrounds.eq(0).show(0).fadeOut(Transition, function(){
$(this).show(0).css({
'background-image': 'url('+img+')'
});
$Backgrounds.eq(1).hide(0);
});
}, 2000
);
Make a wrapper and include both the background div and button div inside it with position absolute and the following CSS styles. This way you can control and animate the background separately from the buttons.
var bg = [
'https://placehold.it/1001x201',
'https://placehold.it/1002x202',
'https://placehold.it/1003x203'
];
$('._container-1').css('background-image', 'url(' + bg[2] + ')');
window.setInterval(
function() {
img = bg.shift();
bg.push(img);
document.getElementsByClassName('_container-1')[0].style.backgroundImage = 'url(' + img + ')';
},
10000
);
window.setInterval(
function() {
img = bg.shift();
bg.push(img);
$('._container-1').fadeOut(600, function() {
$('._container-1').css('background-image', 'url(' + img + ')');
$('._container-1').fadeIn(600);
});
},
17000
);
.wrapper {
position: relative;
width: 100%;
height: 200px;
}
._container-1 {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-size: cover;
background-position: top center;
}
.buttons {
position: absolute;
width: 100%;
text-align: center;
bottom: 0;
left: 0;
}
button {
background: red;
padding: 5px 10px;
border: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="_container-1"></div>
<div class="buttons">
<button type="button">
Button 1
</button>
<button type="button">
Button 2
</button>
</div>
</div>
thank you for your great solution. I am not well familiar with jQuery and have a question about your code:
$Backgrounds.eq(1).hide(0).css({
'background-image': 'url('+img+')'
}).fadeIn(Transition * .9);
means it that the second "background-div" first hides, then get a new background-image and after that it ist fadeIn? And means hide(0) that it immediately hides?
nina_berlini