feat: optimize performance and fix CLS issues
This commit is contained in:
parent
df04844ca2
commit
52f112568c
7 changed files with 88 additions and 17 deletions
|
|
@ -1,7 +1,5 @@
|
||||||
---
|
---
|
||||||
import { Image } from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
import astroIcon from "../assets/astro.svg";
|
|
||||||
import tailwindIcon from "../assets/tailwind.svg";
|
|
||||||
import githubIcon from "../assets/github.svg";
|
import githubIcon from "../assets/github.svg";
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,24 +10,26 @@ import githubIcon from "../assets/github.svg";
|
||||||
<div class="mx-auto max-w-5xl">
|
<div class="mx-auto max-w-5xl">
|
||||||
<div
|
<div
|
||||||
class="relative overflow-hidden rounded-3xl bg-white dark:bg-gray-800 shadow-soft-lg hover:shadow-soft-lg transition-all duration-300"
|
class="relative overflow-hidden rounded-3xl bg-white dark:bg-gray-800 shadow-soft-lg hover:shadow-soft-lg transition-all duration-300"
|
||||||
|
style="min-height: 300px;"
|
||||||
>
|
>
|
||||||
<div class="relative flex flex-col md:flex-row items-center md:items-end">
|
<div class="relative flex flex-col md:flex-row items-center md:items-end">
|
||||||
<!-- Photo Section -->
|
<!-- Photo Section -->
|
||||||
<div class="w-full md:w-auto flex-shrink-0 order-2 md:order-none">
|
<div class="w-full md:w-auto flex-shrink-0 order-2 md:order-none">
|
||||||
<div class="relative overflow-hidden md:rounded-l-3xl flex justify-center md:block">
|
<div
|
||||||
|
class="relative overflow-hidden md:rounded-l-3xl flex justify-center md:block md:w-[300px]"
|
||||||
|
>
|
||||||
<Image
|
<Image
|
||||||
src={mePhoto}
|
src={mePhoto}
|
||||||
alt="Photo of Lorenzo Iovino"
|
alt="Photo of Lorenzo Iovino"
|
||||||
class="w-48 h-auto md:w-full object-cover object-center"
|
class="w-48 h-48 md:w-[300px] md:h-[300px] object-cover object-center"
|
||||||
width={300}
|
width={300}
|
||||||
height={300}
|
height={300}
|
||||||
quality={90}
|
quality={90}
|
||||||
format="webp"
|
format="webp"
|
||||||
loading="eager"
|
loading="eager"
|
||||||
fetchpriority="high"
|
fetchpriority="high"
|
||||||
|
decoding="sync"
|
||||||
/>
|
/>
|
||||||
<div class="absolute inset-0 to-transparent md:bg-gradient-to-r"></div>
|
|
||||||
<div class="absolute inset-0 to-transparent md:bg-gradient-to-r"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -36,7 +38,7 @@ import githubIcon from "../assets/github.svg";
|
||||||
<div class="space-y-4 md:space-y-6">
|
<div class="space-y-4 md:space-y-6">
|
||||||
<!-- Greeting -->
|
<!-- Greeting -->
|
||||||
<div class="text-center md:text-left">
|
<div class="text-center md:text-left">
|
||||||
<h1 class="mb-3 text-gray-900 dark:text-gray-100">
|
<h1 class="mb-3 text-gray-900 dark:text-gray-100" style="min-height: 2.5rem;">
|
||||||
Hey, I'm <span class="text-gray-900 dark:text-gray-100 font-extrabold"
|
Hey, I'm <span class="text-gray-900 dark:text-gray-100 font-extrabold"
|
||||||
>Lorenzo</span
|
>Lorenzo</span
|
||||||
>!
|
>!
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,7 @@ const currentPath = Astro.url.pathname;
|
||||||
<div
|
<div
|
||||||
id="mobile-menu"
|
id="mobile-menu"
|
||||||
class="hidden md:hidden bg-secondary dark:bg-gray-800 transition-colors duration-200"
|
class="hidden md:hidden bg-secondary dark:bg-gray-800 transition-colors duration-200"
|
||||||
|
style="max-height: 0; overflow: hidden; transition: max-height 0.3s ease-in-out;"
|
||||||
>
|
>
|
||||||
<div class="px-4 py-3 space-y-3">
|
<div class="px-4 py-3 space-y-3">
|
||||||
<a
|
<a
|
||||||
|
|
@ -176,7 +177,15 @@ const currentPath = Astro.url.pathname;
|
||||||
const mobileMenu = document.getElementById("mobile-menu");
|
const mobileMenu = document.getElementById("mobile-menu");
|
||||||
|
|
||||||
mobileMenuButton?.addEventListener("click", () => {
|
mobileMenuButton?.addEventListener("click", () => {
|
||||||
mobileMenu?.classList.toggle("hidden");
|
if (mobileMenu?.classList.contains("hidden")) {
|
||||||
|
mobileMenu.classList.remove("hidden");
|
||||||
|
mobileMenu.style.maxHeight = "500px";
|
||||||
|
} else if (mobileMenu) {
|
||||||
|
mobileMenu.style.maxHeight = "0";
|
||||||
|
setTimeout(() => {
|
||||||
|
mobileMenu?.classList.add("hidden");
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Theme toggle functionality
|
// Theme toggle functionality
|
||||||
|
|
|
||||||
|
|
@ -170,13 +170,32 @@ const fullCanonicalUrl = canonicalUrl || `${siteUrl}${Astro.url.pathname}`;
|
||||||
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
href="https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hiA.woff2"
|
||||||
|
crossorigin
|
||||||
|
/>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
/* Fallback font ottimizzato per ridurre layout shift */
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter-fallback";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400 800;
|
||||||
|
src: local("Arial");
|
||||||
|
ascent-override: 90%;
|
||||||
|
descent-override: 22%;
|
||||||
|
line-gap-override: 0%;
|
||||||
|
size-adjust: 107%;
|
||||||
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400 800;
|
font-weight: 400 800;
|
||||||
font-display: swap;
|
font-display: optional;
|
||||||
src: url(https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hiA.woff2)
|
src: url(https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hiA.woff2)
|
||||||
format("woff2");
|
format("woff2");
|
||||||
unicode-range:
|
unicode-range:
|
||||||
|
|
@ -184,6 +203,17 @@ const fullCanonicalUrl = canonicalUrl || `${siteUrl}${Astro.url.pathname}`;
|
||||||
U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
|
U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
|
||||||
U+FFFD;
|
U+FFFD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Previeni flash of unstyled content */
|
||||||
|
body {
|
||||||
|
font-family:
|
||||||
|
"Inter",
|
||||||
|
"Inter-fallback",
|
||||||
|
-apple-system,
|
||||||
|
BlinkMacSystemFont,
|
||||||
|
"Segoe UI",
|
||||||
|
sans-serif;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
|
||||||
|
|
||||||
<div id="posts-container" class="space-y-8">
|
<div id="posts-container" class="space-y-8">
|
||||||
{
|
{
|
||||||
initialPosts.map((post: BlogPost) => (
|
initialPosts.map((post: BlogPost, index: number) => (
|
||||||
<article class="bg-white dark:bg-gray-800 rounded-2xl shadow-soft-lg overflow-hidden hover:shadow-soft-lg transition-all duration-300">
|
<article class="bg-white dark:bg-gray-800 rounded-2xl shadow-soft-lg overflow-hidden hover:shadow-soft-lg transition-all duration-300">
|
||||||
<div class="block">
|
<div class="block">
|
||||||
{post.data.heroImage && (
|
{post.data.heroImage && (
|
||||||
|
|
@ -118,10 +118,12 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
|
||||||
src={post.data.heroImage}
|
src={post.data.heroImage}
|
||||||
alt={post.data.title}
|
alt={post.data.title}
|
||||||
class="w-full h-full object-cover hover:scale-105 transition-transform duration-300"
|
class="w-full h-full object-cover hover:scale-105 transition-transform duration-300"
|
||||||
width={1200}
|
width={760}
|
||||||
height={630}
|
height={570}
|
||||||
quality={70}
|
quality={80}
|
||||||
format="webp"
|
format="webp"
|
||||||
|
loading={index === 0 ? "eager" : "lazy"}
|
||||||
|
fetchpriority={index === 0 ? "high" : undefined}
|
||||||
/>
|
/>
|
||||||
<div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent" />
|
<div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent" />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -159,7 +161,7 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
|
||||||
<p class="text-gray-700 dark:text-gray-300 text-lg leading-relaxed mb-4">
|
<p class="text-gray-700 dark:text-gray-300 text-lg leading-relaxed mb-4">
|
||||||
{post.data.description}
|
{post.data.description}
|
||||||
</p>
|
</p>
|
||||||
<div class="flex items-center text-secondary-800 dark:text-primary font-medium">
|
<div class="flex items-center text-secondary-700 dark:text-primary font-medium">
|
||||||
Read more
|
Read more
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|
@ -220,6 +222,9 @@ const initialPosts: BlogPost[] = sortedPosts.slice(0, 6);
|
||||||
src="${post.data.heroImage}"
|
src="${post.data.heroImage}"
|
||||||
alt="${post.data.title}"
|
alt="${post.data.title}"
|
||||||
class="w-full h-full object-cover hover:scale-105 transition-transform duration-300"
|
class="w-full h-full object-cover hover:scale-105 transition-transform duration-300"
|
||||||
|
loading="lazy"
|
||||||
|
width="760"
|
||||||
|
height="570"
|
||||||
/>
|
/>
|
||||||
<div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent"></div>
|
<div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -82,10 +82,12 @@ const heroImageSrc = entry.data.heroImage?.src || mePhoto.src;
|
||||||
src={entry.data.heroImage}
|
src={entry.data.heroImage}
|
||||||
alt={entry.data.title}
|
alt={entry.data.title}
|
||||||
class="w-full h-full object-cover"
|
class="w-full h-full object-cover"
|
||||||
width={1200}
|
width={824}
|
||||||
height={630}
|
height={618}
|
||||||
quality={70}
|
quality={80}
|
||||||
format="webp"
|
format="webp"
|
||||||
|
loading="eager"
|
||||||
|
fetchpriority="high"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,15 @@
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
|
font-family:
|
||||||
|
"Inter",
|
||||||
|
-apple-system,
|
||||||
|
BlinkMacSystemFont,
|
||||||
|
"Segoe UI",
|
||||||
|
Roboto,
|
||||||
|
"Helvetica Neue",
|
||||||
|
Arial,
|
||||||
|
sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Typography base */
|
/* Typography base */
|
||||||
|
|
@ -17,6 +26,9 @@
|
||||||
"kern" 1,
|
"kern" 1,
|
||||||
"liga" 1,
|
"liga" 1,
|
||||||
"calt" 1;
|
"calt" 1;
|
||||||
|
/* Previene layout shift durante il caricamento del font */
|
||||||
|
font-synthesis: none;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Headings ottimizzati */
|
/* Headings ottimizzati */
|
||||||
|
|
@ -32,6 +44,8 @@
|
||||||
"liga" 1,
|
"liga" 1,
|
||||||
"calt" 1,
|
"calt" 1,
|
||||||
"ss01" 1;
|
"ss01" 1;
|
||||||
|
/* Contenimento del layout per prevenire shift */
|
||||||
|
contain: layout style paint;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
|
|
@ -85,4 +99,15 @@
|
||||||
.text-pretty {
|
.text-pretty {
|
||||||
text-wrap: pretty;
|
text-wrap: pretty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Previeni layout shift per elementi con contenuto dinamico */
|
||||||
|
.prevent-shift {
|
||||||
|
contain: layout style paint;
|
||||||
|
content-visibility: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ottimizza rendering immagini */
|
||||||
|
img {
|
||||||
|
contain: size layout paint;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue