Debugging story: taming Firefox's quirks with Bootstrap 5
Published on 14 July 2025
- The battlefield: a mockup, three browsers, multiple renderings
- Problem 1: The floating card of the "Hero" section
- Problem 2: The cannibal navigation bar
- Problem 3 : Anarchic typography
- Problem 4: The navigation bar that overflows
- Problem 5: The invisible hamburger menu
- Conclusion: the lessons of relentless debugging
|
Reading time : about 7 minutes Level : Intermediate |
In this detailed case study, we will dissect the most common and sometimes most frustrating browser compatibility issues encountered when creating a UI mockup with Bootstrap 5.2. From handling Flexbox to the subtlety of font rendering, discover our debugging journey to turn a shaky design under Firefox into a pixel-perfect experience across all browsers.
The battlefield: a mockup, three browsers, multiple renderings
Every front-end developer knows this feeling. After hours of work, the mockup is finally perfect. Alignments are crisp, typography is elegant, animations are smooth. You let out a sigh of satisfaction, you admire your work on Chrome (or Brave, or Edge), then, just to be safe, you open the project on Firefox. And there, it’s drama. Elements overflowing, broken alignments, fonts with chaotic sizes… the beautiful harmony has flown away.
It’s precisely the scenario we faced when developing a new portfolio interface. The brief was simple: a modern, responsive home page, with a theme selector (light, dark, and high contrast), using vanilla JavaScript and the latest version of Bootstrap 5.2.
This article is not a list of miracle solutions. It is the logbook of our debugging session, a deep dive into the "why" of rendering differences between the Blink (Chromium, Brave) and Gecko (Firefox) engines, and the demonstration that robust, modern solutions are always better than hasty patches.
@startuml
left to right direction
actor "Front-End Developer" as Dev
rectangle "Bootstrap 5 UI mockup" {
usecase "Fix Flexbox alignment" as UC1
usecase "Adjust padding dynamically (JS)" as UC2
usecase "Control typography (clamp())" as UC3
usecase "Fix the menu overflow" as UC4
usecase "Make the menu icon visible" as UC5
}
actor "Firefox browser" as Firefox
Dev -- (UC1)
Dev -- (UC2)
Dev -- (UC3)
Dev -- (UC4)
Dev -- (UC5)
(UC1) ..> Firefox : <<extend>>
(UC2) ..> Firefox : <<extend>>
(UC3) ..> Firefox : <<extend>>
(UC4) ..> Firefox : <<extend>>
(UC5) ..> Firefox : <<extend>>
note right of Firefox : Révèle les problèmes de compatibilité
@enduml
@startuml
!theme plain
package "Front-end solution" {
component "HTML (FTL Templates)" as HTML
component "script.js" as JS
component "styles.css" as CSS
interface "DOM manipulation" as iDOM
interface "CSS corrections" as iCSS
}
package "Framework" {
component "Bootstrap 5.2" as BS
interface "CSS Variables" as iVars
interface "Utility Classes" as iUtils
}
HTML ..> iDOM : nécessite
JS ..> iDOM : réalise
HTML ..> iCSS : nécessite
CSS ..> iCSS : réalise
CSS ..> iVars : nécessite
BS ..> iVars : fournit
HTML ..> iUtils : utilise
BS ..> iUtils : fournit
note right of JS
- Mesure la hauteur de la navbar
- Applique le padding dynamiquement
end note
note right of CSS
- Utilise clamp() pour la typographie
- Réduit les marges du menu
- Surcharge l'icône du menu via les variables
end note
@enduml
Problem 1: The floating card of the "Hero" section
The first bug was also the most visible. The welcome section ("hero") is composed of two columns: on the left, the main title; on the right, a presentation card.
-
The symptom:On Chrome and Brave, the two columns were perfectly vertically centered. On Firefox, the right card inexplicably fell below the left text.
-
The investigation:The HTML code, however, seemed simple and correct, using Bootstrap’s standard classes.
<section id="home" class="hero-section">
<div class="container">
<!-- Cette ligne est la clé du problème -->
<div class="row align-items-center min-vh-100">
<div class="col-lg-6">
<!-- Contenu de gauche -->
</div>
<div class="col-lg-6">
<!-- Carte de droite -->
</div>
</div>
</div>
</section>
Our custom CSS for`.hero-section`was defining`display: flex` et align-items: center, and the class`min-vh-100`gave it a minimum height to the line (div.row). So why was Firefox refusing to center the columns?
-
The root cause :It’s a textbook case of how rendering engines interpret implied heights. The`<section>`had a`min-height`, but no`height`explicit. To apply`align-items-center`inside`div.row`, Firefox needs to know the reference height of this container. Like its parents (
div.containeret la `<section>`herself) had no heightstrict, Firefox was lost. The Blink engine, more permissive, manages to "guess" the intention and to center the elements. Gecko, more faithful to the specification, does not do that. -
The solution:Make the height explicit. We forced the`.container` et le `.row`to take up 100 % of the height of their respective parent using the utility class`h-100`of Bootstrap.
<section id="home" class="hero-section">
<div class="container h-100">
<div class="row align-items-center min-vh-100 h-100">
<!-- ... -->
</div>
</div>
</section>
|
When a`align-items`Flexbox does not work as expected on the vertical axis, always check that the container has a height ( |
Problem 2: The cannibal navigation bar
-
The symptom: Le `padding`was sufficient on Chrome, but not on Firefox, where the title was always partially hidden.
-
The root cause:Using a "magic number" (
80px) is a very bad practice. The height of an element such as a navigation bar can vary by a few pixels from one browser to another due to subtle differences in font rendering, spacing, or even user settings. Relying on a fixed value is a recipe for a fragile design. -
The solution:A dynamic and foolproof solution in JavaScript. We wrote a small script to:
-
Measure the actual height of the navigation bar after rendering the page.
-
Apply this measured height as`padding-top`to the Hero section.
-
Re-execute this function on every window resize to adapt to changes (such as switching to the hamburger menu).
document.addEventListener('DOMContentLoaded', function() {
function adjustHeroPadding() {
const navbar = document.querySelector('.navbar.fixed-top');
const heroSection = document.querySelector('.hero-section');
if (navbar && heroSection) {
const navbarHeight = navbar.offsetHeight;
heroSection.style.paddingTop = navbarHeight + 'px';
}
}
// Ajuster au chargement et au redimensionnement
adjustHeroPadding();
window.addEventListener('resize', adjustHeroPadding);
});
@startuml
title Solution to the problem of the cannibal navigation bar
actor Utilisateur
participant "Browser" as Browser
participant "script.js" as JS
participant "DOM" as DOM
Utilisateur -> Browser: Charge la page
activate Browser
Browser -> JS: Déclenche l'événement 'DOMContentLoaded'
activate JS
JS -> DOM: querySelector('.navbar.fixed-top')
activate DOM
DOM --> JS: Retourne l'élément Navbar
deactivate DOM
JS -> DOM: querySelector('.hero-section')
activate DOM
DOM --> JS: Retourne l'élément Hero
deactivate DOM
JS -> DOM: navbar.offsetHeight
activate DOM
DOM --> JS: Retourne la hauteur calculée (ex: 83px)
deactivate DOM
JS -> DOM: heroSection.style.paddingTop = "83px"
activate DOM
deactivate DOM
deactivate JS
deactivate Browser
... Plus tard ...
Utilisateur -> Browser: Redimensionne la fenêtre
activate Browser
Browser -> JS: Déclenche l'événement 'resize'
activate JS
JS -> JS: Exécute à nouveau adjustHeroPadding()
note right of JS: Le processus de mesure et\nd'application du padding se répète.
deactivate JS
deactivate Browser
@enduml
In parallel, of course we have removed the rule`padding-top: 80px;`of our file`styles.css`.
Problem 3 : Anarchic typography
-
The symptom:On Firefox, the font of the title "Développeur Formateur…" was gigantic, almost shocking, whereas it was harmonious on the other browsers.
-
Root cause:The title used a class`display-4`of Bootstrap. These classes use responsive font sizes, often based on the unit`rem`and media queries. Once again, Firefox’s rendering algorithm, combined with the "Inter" font, resulted in a much larger size calculation on our 1920x1080 resolution.
-
The solution:Take back control with the CSS function`clamp()
. This function is a game-changer for fluid typography. It allows you to define a font size with three values: a minimum size, a "preferred" size (which adapts to the viewport width,`vw), and a maximum size.
.hero-content h1 {
color: var(--text-primary);
line-height: 1.2;
/*
Min: 2rem
Préférée: s'adapte à la vue
Max: 2.5rem (40px)
*/
font-size: clamp(2rem, 1.2rem + 1.5vw, 2.5rem);
}
With`clamp(), we were able to tell the browser: "Make the font grow with the screen, but do not exceedneverthe limit of`2.5rem. This instantly harmonized the rendering across all browsers, giving us absolute control over the final aesthetic.
Problem 4: The navigation bar that overflows
It was the problem that gave us the most trouble and ultimately revealed the deep nature of the rendering micro-differences.
-
The symptom:On a 1920×1080 screen, the last links in the menu ("Blog", "Contact") were pushed off‑screen to the right, but only in Firefox.
-
Profound cause :After several unsuccessful attempts (changing Bootstrap breakpoints of`lg` à
xl`then`xxl), we understood. The cause was not the Bootstrap logic, but a simple width calculation. On Firefox, the sum of the widths of all the links, including their`padding` et `margin`To the nearest sub-pixel, it was slightly greater than 1920 pixels. On Chrome, this same sum was slightly less. We were missing a few pixels. -
The solution:A surgical reduction of spacing. Since it was out of the question to specifically target Firefox with outdated CSS "hacks", the only clean solution was to find a common style that works everywhere. So we slightly reduced the horizontal margins and padding of each navigation link.
/* La version finale, légèrement plus compacte */
.navbar-nav .nav-link {
font-size: 0.9rem; /* 90% de la taille de base */
color: var(--text-primary) !important;
font-weight: 500;
margin: 0 0.2rem;
padding: 0.5rem 0.5rem !important;
border-radius: 0.375rem;
transition: all 0.3s ease;
}
This reduction, virtually invisible to the naked eye on a single element, collectively gave us the necessary space for all links to fit within the frame in Firefox, while preserving an almost identical appearance on other browsers.
Problem 5: The invisible hamburger menu
The last problem, and by no means the least, concerned mobile accessibility.
-
The symptom:In responsive mode (hamburger menu), the menu icon was invisible on the 'dark' and 'high-contrast' themes.
-
The root cause:The icon of the Bootstrap 5 menu is a`background-image`(a URL-encoded SVG). By default, the color of its stroke is dark, optimized for a light background. It does not automatically adapt to theme changes.
-
The solution:Use Bootstrap CSS variables to override the icon. We have defined a new SVG icon, but this time with a white stroke.
#ffffff), and we applied it specifically when the themes`dark` ou `high-contrast`are active.
/* ======================
Fix pour l'icône du menu Burger (Blanc)
====================== */
[data-bs-theme="dark"] .navbar-toggler-icon,
[data-bs-theme="high-contrast"] .navbar-toggler-icon {
--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23ffffff' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}
|
Customizing Bootstrap components like this one is increasingly done via overriding CSS variables ( |
Conclusion: the lessons of relentless debugging
This journey, although sometimes frustrating, is rich in lessons. Each solved problem reinforces a fundamental truth of web development:Nothing replaces a rigorous cross-browser test..
@startmindmap + Débogage Cross-Browser : Bootstrap 5 ++ **Conflit :** Chrome (Blink) vs Firefox (Gecko) ++ **Problème 1 : Alignement Hero** +++ Cause : Hauteur implicite +++ Solution : Classe `.h-100` ++ **Problème 2 : Navbar Cannibale** +++ Cause : "Magic Number" (padding fixe) +++ Solution : JS `offsetHeight` ++ **Problème 3 : Typographie Géante** +++ Cause : Rendu des `rem` +++ Solution : CSS `clamp()` ++ **Problème 4 : Menu qui déborde** +++ Cause : Calcul de largeur sub-pixel +++ Solution : Réduction des marges/paddings ++ **Problème 5 : Icône Invisible** +++ Cause : SVG non adaptable au thème +++ Solution : Surcharge de variable CSS ++ **Leçons Clés** +++ Firefox force un code robuste +++ Fuir les "magic numbers" +++ Maîtriser la typographie fluide +++ Personnaliser via les variables CSS @endmindmap
-
Firefox is an ally:Its greater fidelity to CSS standards forces us to write code that is more robust and less ambiguous.
-
Avoid the "magic numbers" :Fixed values (such as`padding-top: 80px`) are ticking time bombs. Always prefer dynamic solutions (JavaScript) or relative ones (Flexbox, Grid).
-
Master your typography:Use`clamp()`for full control over the size of responsive fonts.
-
Think in "components":To customize Bootstrap, override its CSS variables instead of adding many rules that override the framework.
-
Do not target a browser:The solution is almost never to make a \"hack\" for a specific browser, but to find a common style that works everywhere.
Finally, the mockup is now solid, predictable, and ready to be integrated into a templating system. Every bug fixed was not a failure, but a step towards better quality code.