Largest contentful paint is one big gatsby-background-image and very slow - reactjs

For those stumbling on this question wondering how to improve their lighthouse score in general, I posted an answer on this topic on another question with lots of general tips.
I'm running PageSpeed insights and my biggest problem is the largest contentful paint, at about 8-10 seconds. Below they list my largest contentful paint element
Largest Contentful Paint element 1 element found
This is the largest contentful element painted within the viewport. Learn More
Element
This is the a paragraph that appears above here
<section class="mainBgImage gbi--716926567-eDXcajFRMpQ2F1s7wNgLk1" style="background-position:center top;background-repeat:no-repeat;background-size:cover;position:relative;opacity:0.99" role="img">
This element is an image that spans my whole website in the background. It was originally a 1.2 MB png that i load using ...GatsbyImageSharpFluid_withWebp_noBase64 with a maxWidth of 1950.
This is the code for how I render it
import BackgroundImage from 'gatsby-background-image';
...
<BackgroundImage
Tag="section"
role="img"
className='mainBgImage'
fadeIn={false}
// style={{objectFit: 'contain', width: '100%' }}
style={{
opacity: 0.03,
backgroundPosition: "center top",
}}
fluid={wheatImgProps}
>
{children}
</BackgroundImage>
And this is the static graphql query
const data = useStaticQuery(graphql
`query LayoutQuery {
wheatImg: file(
extension: {regex: "/(jpg)|(jpeg)|(png)/"},
name: {eq: "wheat-background"}
) {
childImageSharp {
fluid(maxWidth: 1950) {
...GatsbyImageSharpFluid_withWebp_noBase64
}
}
}
}
`
)

Turns out the solution was to split my background image into 2. One for "above the fold"(Whats visible without scrolling) and one for "below the fold". I also found this image compressor website to be one of the most helpful and straight forward when it came to reducing my file size.
I then created an absolutely positioned div which looked like
const BGImg = ({img, className}:{img:FluidObject, className?:string}) => (
<Img
Tag="section"
className={className}
durationFadeIn={250}
style={{
opacity: 0.03,
minWidth:"100%",
objectFit: 'cover',
objectPosition: "center top",
}}
fluid={img}
/>
)
...
<div id='layout'>
<div id='bgImageContainer'>
<BGImg img={above_the_fold_bg} />
<BGImg img={below_the_fold_bg} />
</div>
...
with styling that looked like
#bgImageContainer{
position: absolute;
z-index: -999;
min-width:100%;
min-height:100%;
display:flex;
flex-direction: column;
justify-content: flex-end;
align-self: stretch;
}
#layout{
overflow: hidden;
position: relative;
}

Related

Framer Motion - fade out element according to scroll position

Using framer motion, I am trying to fade in an object when it enters the viewport. Then I would like it to stay fixed for a while and eventually fade out.
So far I have only managed to fade the element in and fade it out when it leaves the viewport, which is too late. I was not able to figure out how to fix the element at a certain scroll position.
Here is what I have achieved:
This is what I am trying to achieve:
This is the Code Sandbox: https://codesandbox.io/s/vigorous-dawn-q4figi?file=/src/App.js
Here is the code:
export default function App() {
const [ref, inView] = useInView({
threshold: 0.5,
triggerOnce: false
});
const variants = {
visible: { opacity: 1, scale: 1, y: 0 },
hidden: {
opacity: 0,
scale: 0.65,
y: 50
}
};
return (
<div className="App">
<div style={{ height: 500 }} />
<motion.div
animate={inView ? "visible" : "hidden"}
variants={variants}
exit="hidden"
transition={{ duration: 2, ease: "easeOut" }}
className="box"
ref={ref}
/>
</div>
);
}
I would be very thankful for any kind of help!
You're almost there, just a couple of tweaks - mostly CSS for how you should position your animated element.
body {
margin: 0;
}
.App {
height: 300vh;
display: flex;
justify-content: center;
align-items: center;
background-color: #3b6fe0;
}
.box {
width: 200px;
height: 200px;
background-color: #fff;
border-radius: 20px;
}
Here's a full demo: https://codesandbox.io/s/flamboyant-sara-ce4pvx?file=/src/App.js
Note: it's a bit buggy to combine the useInView hook with the scale animation, as scaling the element will affect the in-view threshold. You could also consider use-scroll as an alternative, it may be harder to implement but provide more control over the animation.

scss and flexbox with logos in two different layouts

I am runnning across an issue in which I am not sure how to solve.
I have a grid system doing the following, BUT I will do a standard "div" solution. But here is my dilemna.
I have a "LogoComponent" That displays my companies logo on the left, and a partner's logo on the right.
I have two headers that display in two different conditions.
Centered Display (just the logos)
Left Aligned Display (left aligned logos, with other content on the right)
Caveats: the "partner logo" needs to confine within the div/space as sometimes the svg's are large, so I "can" offer a height, but not a width.
The image shows the two views. The "LogoComponent" I am having an issue as I was using a flexbox, but not sure that is gonna work since why I try to make it "left" as a component, it moves off the container div. Any ideas how to solve this?
I can solve it, but I feel it will be too generalized, as I'm looking to make this "LogoComponent" be wide enough for the logos, and then appropriately resize if the partner logo is there or not.
As said in the comment, you can center LogoComponent using margin: 0 auto; when it's the :only-child.
If it's not the only child, using margin-right: auto; will push all other content to the right as we are in a flex container.
.parent {
display: flex;
}
.LogoComponent {
margin-right: auto;
}
.LogoComponent:only-child {
margin: 0 auto;
}
/* for styling only */
.LogoComponent {
width: 50px;
height: 50px;
background-color: lightblue;
}
/* for styling only */
.OtherContent {
min-width: 200px;
background-color: lightgreen;
}
<div class="parent">
<div class="LogoComponent"></div>
</div>
<hr>
<div class="parent">
<div class="LogoComponent"></div>
<div class="OtherContent"></div>
</div>

React image change with slider (Not carousel)

Good day!
I am working on a project in React where I have several images that look almost the same, but differ in some way. Here are the four images
What I want to do is to have a slider that changes the image on slide. So the image essentially gets replaced with the next one "in place" - if that makes sense. Thus, it's not a carousel, because the image is not moving, it's being replaced by another image. Here is a mock-up of what I want to do
The images are maps with locations that change each year. So I want the user to see how the locations change without the image moving.
I hope this makes sense. Are there any libraries or principles I should look at?
Thanks!
You question is very vague. There are many ways to achieve what you want. From the tag you used i assume that you are using React? I've created a basic example on what it could look like.
One way is to position the images on top of each other and toggle the visibility/opacity, like so:
class App extends React.Component {
state = {
imageIndex: 0,
}
setIndex = (e) => {
this.setState({imageIndex: parseInt(e.target.value)});
}
render() {
const {imageIndex} = this.state;
return (
<div>
<div className="image-wrapper">
<img style={{opacity: imageIndex === 0 ? 1 : 0}} src="https://via.placeholder.com/150/ff0"/>
<img style={{opacity: imageIndex === 1 ? 1 : 0}} src="https://via.placeholder.com/150/f00"/>
<img style={{opacity: imageIndex === 2 ? 1 : 0}} src="https://via.placeholder.com/150/f0f"/>
<img style={{opacity: imageIndex === 3 ? 1 : 0}} src="https://via.placeholder.com/150/0f0"/>
</div>
<input
type="range"
value={imageIndex}
min="0"
max="3"
onChange={this.setIndex}
/>
</div>
);
}
};
ReactDOM.render(<App/>, document.body);
img {
position: absolute;
width: 100%;
height: 100%;
transition: opacity .3s;
}
.image-wrapper {
width: 150px;
height: 150px;
position: relative;
}
input[type="range"] {
width: 150px;
}
html,
body {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
<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>
Another way would be to render the image that is currently shown to the user, which can make animation handling a bit iffy, as unmounting needs to be delayed (in that case you should take a look at a React Animation Framework, e.g. React Transition Group) The image should be positioned with css in a way that it does not move.
I hope you can salvage something from this answer.

How to manage Z-index with 4 layers in React?

How would one go for setting up the z-index, so that the 4 layers are as follow:
background color
logoImg (png with opacity 00.7) (!)
circleImg (png)
coundownClock (text)
I tried changing z-index in every possible way, and I can not get that the 3. circleImg & 4. coundownClock overlap.
#1. background color & #2. logoImg are set correctly as background
TimerScreen.js:
import React from 'react';
import UIfx from 'uifx';
import Logo from "../images/logo.png";
import Circle from "../images/circle.png";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
class TimerScreen extends React.Component {
state = {
minutes: 3,
seconds: 0,
reps: 3
}
render() {
const { minutes, seconds, reps } = this.state
return (
<div className="mainDiv" >
<img
className="logoImg"
style={{
width: "100%",
opacity: "0.07",
position: "absolute",
zIndex: "-1"
}}
src={Logo}
alt="berolina-stralau logo"
/>
<div className="coundownClock"> { minutes < 10 ? `0${ minutes }` : minutes }:{ seconds < 10 ? `0${ seconds }` : seconds } </div>
<img id="circleImg" src={Circle} />
<div className="repetitionsCount"> <i>reps left: {reps}</i> </div>
<div id="buttonDiv">
<Link to="/TimerScreen"
className="goButton">PAUSE</Link>
</div>
<br />
</div>
);
}
}
export default TimerScreen;
App.css part:
circleImg {
width: 100%;
margin-bottom: 40px;
position: "absolute";
z-index: "0";
}
.coundownClock {
display: flex;
justify-content: center;
font-size: 111px;
font-weight: bold;
position: "relative";
z-index: "1";
}
Full code on github.com FilipZafran/Interval-Timer
Definition from https://www.w3schools.com/cssref/pr_pos_z-index.asp:
The z-index property specifies the stack order of an element.
An element with greater stack order is always in front of an element
with a lower stack order.
Note: z-index only works on positioned elements (position: absolute,
position: relative, position: fixed, or position: sticky).
So make sure your elements have a position and z-index to create the wanted order. If I understood you correctly that would be:
background color -> z-index: 0
logoImg (png with opacity 00.7) (!) -> z-index: 1
circleImg (png) -> z-index: 2
coundownClock (text) -> z-index: 3
background color is then in the back and coundownClock in the front
As an advice: It would be easier to wrap the elements you want to stack above each other in a which has position: relative. Inside you put all the elements you want to stack with position: absolute and the z-index for creating your order

How to get a sider filling whole available height.

I started React based application and i have a ant-design a basic layout with top navbar, sidebar, footer and content area, my code is as following.
<Layout>
<Header>
<TopNavBar/>
</Header>
<Layout>
<Sider className='sider'>
<div >
side nav
</div>
</Sider>
<Content>main content</Content>
</Layout>
<Footer>Footer</Footer>
</Layout>
I want to get a result similar to the representation below, with a sidebar who fill whole available page height
I tried to add the following cCSS class to my sider
.sider {
min-height: 100vh;
position: relative;
z-index: 10;
}
without getting what I want, my sidebar is bigger than available space it's scrolling,the height that exceeds is the height of my header and footer.
I also tried with flexbox but without success, there is any clean way to get the desired result? I thought to do this using the javascript to calculate the available height and set the CSS class.
you can try this code
.menu-style {
overflow: auto;
height: 100vh;
width: 200px;
position: fixed;
left: 0;
background-color: #393f4a;
z-index: 3 ;
border-right : 0;
}

Resources