perf: Defer Bootstrap with inline critical CSS for LCP optimization

- Add grid system (row, col-*) to critical-bootstrap.css to prevent CLS
- Add text utilities, sizing, spacing, and alert component to critical CSS
- Enable CriticalBootstrapService to inline critical Bootstrap in <head>
- Defer bootstrap-subset.min.css (21KB) via media=print + onload
- Fix preload pointing to wrong Bootstrap file (was 227KB, now 147KB)

Expected improvement: ~970ms reduction in render-blocking CSS

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
FrankZamora
2025-11-29 12:05:50 -06:00
parent 5d4523e49a
commit 62a0f17b21
4 changed files with 221 additions and 16 deletions

View File

@@ -84,6 +84,78 @@ button:focus:not(:focus-visible) {
.container { max-width: 1320px; }
}
/* ==========================================================================
GRID SYSTEM (Layout crítico - Previene CLS)
========================================================================== */
.row {
--bs-gutter-x: 1.5rem;
--bs-gutter-y: 0;
display: flex;
flex-wrap: wrap;
margin-top: calc(-1 * var(--bs-gutter-y));
margin-right: calc(-0.5 * var(--bs-gutter-x));
margin-left: calc(-0.5 * var(--bs-gutter-x));
}
.row > * {
flex-shrink: 0;
width: 100%;
max-width: 100%;
padding-right: calc(var(--bs-gutter-x) * 0.5);
padding-left: calc(var(--bs-gutter-x) * 0.5);
margin-top: var(--bs-gutter-y);
}
.col { flex: 1 0 0%; }
.col-auto { flex: 0 0 auto; width: auto; }
.col-1 { flex: 0 0 auto; width: 8.33333333%; }
.col-2 { flex: 0 0 auto; width: 16.66666667%; }
.col-3 { flex: 0 0 auto; width: 25%; }
.col-4 { flex: 0 0 auto; width: 33.33333333%; }
.col-5 { flex: 0 0 auto; width: 41.66666667%; }
.col-6 { flex: 0 0 auto; width: 50%; }
.col-7 { flex: 0 0 auto; width: 58.33333333%; }
.col-8 { flex: 0 0 auto; width: 66.66666667%; }
.col-9 { flex: 0 0 auto; width: 75%; }
.col-10 { flex: 0 0 auto; width: 83.33333333%; }
.col-11 { flex: 0 0 auto; width: 91.66666667%; }
.col-12 { flex: 0 0 auto; width: 100%; }
@media (min-width: 768px) {
.col-md-1 { flex: 0 0 auto; width: 8.33333333%; }
.col-md-2 { flex: 0 0 auto; width: 16.66666667%; }
.col-md-3 { flex: 0 0 auto; width: 25%; }
.col-md-4 { flex: 0 0 auto; width: 33.33333333%; }
.col-md-5 { flex: 0 0 auto; width: 41.66666667%; }
.col-md-6 { flex: 0 0 auto; width: 50%; }
.col-md-7 { flex: 0 0 auto; width: 58.33333333%; }
.col-md-8 { flex: 0 0 auto; width: 66.66666667%; }
.col-md-9 { flex: 0 0 auto; width: 75%; }
.col-md-10 { flex: 0 0 auto; width: 83.33333333%; }
.col-md-11 { flex: 0 0 auto; width: 91.66666667%; }
.col-md-12 { flex: 0 0 auto; width: 100%; }
}
@media (min-width: 992px) {
.col-lg-1 { flex: 0 0 auto; width: 8.33333333%; }
.col-lg-2 { flex: 0 0 auto; width: 16.66666667%; }
.col-lg-3 { flex: 0 0 auto; width: 25%; }
.col-lg-4 { flex: 0 0 auto; width: 33.33333333%; }
.col-lg-5 { flex: 0 0 auto; width: 41.66666667%; }
.col-lg-6 { flex: 0 0 auto; width: 50%; }
.col-lg-7 { flex: 0 0 auto; width: 58.33333333%; }
.col-lg-8 { flex: 0 0 auto; width: 66.66666667%; }
.col-lg-9 { flex: 0 0 auto; width: 75%; }
.col-lg-10 { flex: 0 0 auto; width: 83.33333333%; }
.col-lg-11 { flex: 0 0 auto; width: 91.66666667%; }
.col-lg-12 { flex: 0 0 auto; width: 100%; }
}
/* Gutter utilities */
.g-0, .gx-0 { --bs-gutter-x: 0; }
.g-0, .gy-0 { --bs-gutter-y: 0; }
.g-3, .gx-3 { --bs-gutter-x: 1rem; }
.g-3, .gy-3 { --bs-gutter-y: 1rem; }
/* ==========================================================================
FLEXBOX UTILITIES (Layout crítico)
========================================================================== */
@@ -96,10 +168,16 @@ button:focus:not(:focus-visible) {
.d-block {
display: block !important;
}
.d-inline-block {
display: inline-block !important;
}
.flex-wrap {
flex-wrap: wrap !important;
}
.flex-column {
flex-direction: column !important;
}
.justify-content-center {
justify-content: center !important;
@@ -107,31 +185,98 @@ button:focus:not(:focus-visible) {
.justify-content-between {
justify-content: space-between !important;
}
.justify-content-start {
justify-content: flex-start !important;
}
.justify-content-end {
justify-content: flex-end !important;
}
.align-items-center {
align-items: center !important;
}
.align-items-start {
align-items: flex-start !important;
}
.align-items-end {
align-items: flex-end !important;
}
.gap-2 {
gap: 0.5rem !important;
}
.gap-3 {
gap: 1rem !important;
}
/* ==========================================================================
SPACING UTILITIES (Margin/Padding críticos)
========================================================================== */
.m-0 { margin: 0 !important; }
.m-auto { margin: auto !important; }
.mb-0 { margin-bottom: 0 !important; }
.mb-1 { margin-bottom: 0.25rem !important; }
.mb-2 { margin-bottom: 0.5rem !important; }
.mb-3 { margin-bottom: 1rem !important; }
.mb-4 { margin-bottom: 1.5rem !important; }
.mt-0 { margin-top: 0 !important; }
.mt-2 { margin-top: 0.5rem !important; }
.mt-3 { margin-top: 1rem !important; }
.me-1 { margin-right: 0.25rem !important; }
.me-2 { margin-right: 0.5rem !important; }
.me-3 { margin-right: 1rem !important; }
.ms-2 { margin-left: 0.5rem !important; }
.ms-3 { margin-left: 1rem !important; }
.py-3 {
padding-top: 1rem !important;
padding-bottom: 1rem !important;
.mx-auto { margin-left: auto !important; margin-right: auto !important; }
.p-0 { padding: 0 !important; }
.p-2 { padding: 0.5rem !important; }
.p-3 { padding: 1rem !important; }
.py-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; }
.py-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; }
.py-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; }
.px-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; }
.px-3 { padding-left: 1rem !important; padding-right: 1rem !important; }
.px-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; }
/* ==========================================================================
SIZING UTILITIES (Width/Height críticos)
========================================================================== */
.w-100 { width: 100% !important; }
.w-auto { width: auto !important; }
.h-100 { height: 100% !important; }
.h-auto { height: auto !important; }
/* ==========================================================================
TEXT UTILITIES (Críticos para layout)
========================================================================== */
.text-center { text-align: center !important; }
.text-start { text-align: left !important; }
.text-end { text-align: right !important; }
.text-white { color: #fff !important; }
.text-muted { color: var(--bs-secondary-color, #6c757d) !important; }
.fw-normal { font-weight: 400 !important; }
.fw-medium { font-weight: 500 !important; }
.fw-semibold { font-weight: 600 !important; }
.fw-bold { font-weight: 700 !important; }
.fs-5 { font-size: 1.25rem !important; }
.fs-6 { font-size: 1rem !important; }
.small { font-size: 0.875em !important; }
@media (min-width: 768px) {
.text-md-start { text-align: left !important; }
.text-md-center { text-align: center !important; }
.text-md-end { text-align: right !important; }
}
/* ==========================================================================
@@ -384,6 +529,48 @@ button:focus:not(:focus-visible) {
.text-decoration-underline {
text-decoration: underline !important;
}
.text-decoration-none {
text-decoration: none !important;
}
/* ==========================================================================
IMAGE UTILITIES
========================================================================== */
.img-fluid {
max-width: 100%;
height: auto;
}
/* ==========================================================================
ALERT COMPONENT (Above-the-fold notifications)
========================================================================== */
.alert {
--bs-alert-padding-x: 1rem;
--bs-alert-padding-y: 1rem;
--bs-alert-margin-bottom: 1rem;
--bs-alert-border-radius: 0.375rem;
position: relative;
padding: var(--bs-alert-padding-y) var(--bs-alert-padding-x);
margin-bottom: var(--bs-alert-margin-bottom);
border: 1px solid transparent;
border-radius: var(--bs-alert-border-radius);
}
.alert-warning {
--bs-alert-color: #664d03;
--bs-alert-bg: #fff3cd;
--bs-alert-border-color: #ffecb5;
color: var(--bs-alert-color);
background-color: var(--bs-alert-bg);
border-color: var(--bs-alert-border-color);
}
.alert-info {
--bs-alert-color: #055160;
--bs-alert-bg: #cff4fc;
--bs-alert-border-color: #b6effb;
color: var(--bs-alert-color);
background-color: var(--bs-alert-bg);
border-color: var(--bs-alert-border-color);
}
/* ==========================================================================
BUTTON CLOSE (Dismiss notification)