Table of Contents
- Introduction to Web Debugging
- Browser Developer Tools
- HTML Debugging Techniques
- CSS Debugging Techniques
- Layout Debugging
- Responsive Design Testing
- Performance Debugging
- Accessibility Testing
- Cross-Browser Testing
- Validation Tools
- Automated Testing
- Debugging Workflows
- Common Issues and Solutions
- Best Practices
Introduction to Web Debugging
Debugging HTML and CSS is a critical skill for web developers. Understanding how to identify, isolate, and fix issues efficiently can save hours of frustration and lead to better, more maintainable code.
Why Debugging Matters
- Identify Issues: Find and fix layout, styling, and functionality problems
- Optimize Performance: Improve load times and rendering efficiency
- Ensure Compatibility: Test across different browsers and devices
- Improve User Experience: Catch issues before users encounter them
- Maintain Code Quality: Keep CSS organized and maintainable
Common Debugging Challenges
/* Common CSS issues to debug */
.element {
/* 1. Specificity conflicts */
color: blue; /* This might be overridden */
}
.override {
color: red; /* More specific? Wins? */
}
/* 2. Inheritance issues */
.parent {
font-size: 16px; /* May not inherit as expected */
}
/* 3. Box model problems */
.box {
width: 100%; /* Padding and border affect actual width */
padding: 20px; /* Box-sizing not accounted for */
}
/* 4. Layout collapsing */
.float-left {
float: left; /* Parent collapses */
}
/* 5. Z-index stacking */
.modal {
z-index: 1000; /* May not appear above other elements */
}
Browser Developer Tools
Chrome DevTools Overview
// Access Chrome DevTools
// - Windows/Linux: F12 or Ctrl+Shift+I
// - Mac: Cmd+Option+I
// Console tab - Run JavaScript commands
console.log('Debugging message');
console.table(data); // Display data in table format
console.trace(); // Show call stack
// Elements tab - Inspect and modify DOM
// - Right-click any element → Inspect
// - Modify HTML/CSS in real-time
// - See computed styles
// - Track applied CSS rules
Elements Panel Deep Dive
/* Elements panel features */
/* 1. Computed Styles */
.element {
/* See final applied styles */
color: blue; /* May be overridden */
}
/* 2. Styles Panel */
.element {
/* View all applied rules */
/* Toggle properties on/off */
/* Add new properties */
/* See specificity values */
font-size: 16px;
padding: 10px;
}
/* 3. Box Model Visualization */
.box-model {
width: 200px;
height: 100px;
padding: 20px;
margin: 10px;
border: 2px solid black;
}
Console Panel Techniques
// Console debugging techniques
// 1. Inspect elements programmatically
const element = document.querySelector('.my-element');
console.log(element); // Log element
console.dir(element); // Log element properties
// 2. Get computed styles
const styles = getComputedStyle(element);
console.log(styles.color); // Get specific property
console.log(styles.getPropertyValue('margin'));
// 3. Measure elements
const rect = element.getBoundingClientRect();
console.log(rect); // Position and dimensions
// 4. Check for CSS support
console.log(CSS.supports('display', 'grid'));
// 5. Monitor events
monitorEvents(element, 'click'); // Log all click events
unmonitorEvents(element); // Stop monitoring
// 6. Debug with breakpoints
debugger; // Pause execution here
Sources Panel
// Debugging with breakpoints
// 1. Set breakpoints in sources panel
function calculateWidth(element) {
const width = element.offsetWidth;
const padding = getComputedStyle(element).paddingLeft;
debugger; // Execution pauses here
return width + parseInt(padding);
}
// 2. Watch expressions
// Add expressions to watch in the sources panel
// - element.offsetWidth
// - getComputedStyle(element).display
// 3. Call stack inspection
function outer() {
inner();
}
function inner() {
debugger; // View call stack when paused
}
// 4. Step through code
// Use Step Over (F10), Step Into (F11), Step Out (Shift+F11)
Network Panel
// Network panel features
// 1. Monitor resource loading
// - View CSS files
// - Check load order
// - See file sizes
// - Identify blocking resources
// 2. Simulate network conditions
// - Throttling: Slow 3G, Fast 3G, Offline
// - Latency simulation
// - Bandwidth throttling
// 3. Inspect requests
// - Request headers
// - Response headers
// - Preview responses
// - Timing breakdown
// 4. Record network activity
performance.mark('start');
// ... load resources ...
performance.mark('end');
performance.measure('load', 'start', 'end');
Performance Panel
// Performance analysis
// 1. Record performance timeline
console.profile('CSS Rendering');
// ... interact with page ...
console.profileEnd();
// 2. Analyze paint events
// - Layout shifts (Layout Shift)
// - Paint timing
// - Composite layers
// 3. Identify bottlenecks
// - Long tasks (>50ms)
// - Reflows
// - Repaints
// 4. Memory analysis
console.memory; // Check memory usage
HTML Debugging Techniques
Validating HTML Structure
<!-- Common HTML issues to check --> <!-- 1. Missing DOCTYPE --> <!DOCTYPE html> <!-- Required for standards mode --> <!-- 2. Unclosed tags --> <div> <!-- Missing closing tag --> <!-- 3. Improper nesting --> <ul> <div> <!-- Invalid: only li allowed --> <li>Item</li> </div> </ul> <!-- 4. Duplicate IDs --> <div id="main">Content 1</div> <div id="main">Content 2</div> <!-- Invalid: duplicate ID --> <!-- 5. Missing alt attributes --> <img src="image.jpg"> <!-- Should have alt --> <!-- 6. Invalid attributes --> <div class="container" invalid-attr="value"> <!-- Non-standard attribute -->
Debugging HTML with DevTools
<!-- DevTools HTML debugging techniques --> <!-- 1. Edit HTML live --> <div class="test">Original Text</div> <!-- Double-click text in Elements panel → Edit --> <!-- 2. Force element states --> <button class="btn">Hover me</button> <!-- Right-click → Force state → :hover, :active, :focus --> <!-- 3. Scroll into view --> <section id="hidden-section" style="position: absolute; top: 2000px;"> Hidden content </section> <!-- Right-click → Scroll into view --> <!-- 4. Break on attribute modification --> <div id="dynamic" data-status="initial"></div> <!-- Right-click → Break on → attribute modifications --> <!-- 5. Copy as JavaScript path --> <div class="deeply-nested"> <div> <span>Target</span> </div> </div> <!-- Right-click → Copy → Copy JS path -->
DOM Inspection Scripts
// Helpful DOM debugging scripts
// 1. Find all elements with specific attribute
function findElementsWithAttribute(attribute) {
return document.querySelectorAll(`[${attribute}]`);
}
console.log(findElementsWithAttribute('data-testid'));
// 2. Check for empty elements
const emptyElements = document.querySelectorAll('*:empty');
console.log('Empty elements:', emptyElements.length);
// 3. Find elements with inline styles
const inlineStyles = document.querySelectorAll('[style]');
console.log('Inline styles count:', inlineStyles.length);
// 4. Check heading hierarchy
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
console.table(Array.from(headings).map(h => ({
level: h.tagName,
text: h.textContent.trim(),
depth: h.tagName[1]
})));
// 5. Find broken images
document.querySelectorAll('img').forEach(img => {
if (!img.complete || img.naturalWidth === 0) {
console.warn('Broken image:', img.src);
}
});
// 6. Check form fields without labels
const unlabeled = document.querySelectorAll('input:not([type="hidden"]), select, textarea');
unlabeled.forEach(field => {
if (!field.id || !document.querySelector(`label[for="${field.id}"]`)) {
console.warn('Unlabeled field:', field);
}
});
HTML Outline Tools
// Generate HTML outline
function generateOutline() {
const outline = [];
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
headings.forEach(heading => {
const level = parseInt(heading.tagName[1]);
const text = heading.textContent.trim();
const indent = ' '.repeat(level - 1);
outline.push(`${indent}${level}. ${text}`);
});
console.log('Document Outline:');
console.log(outline.join('\n'));
// Check for missing heading levels
let expectedLevel = 1;
for (let i = 0; i < headings.length; i++) {
const currentLevel = parseInt(headings[i].tagName[1]);
if (currentLevel > expectedLevel + 1) {
console.warn(`Skipped heading level: h${expectedLevel + 1} missing`);
}
expectedLevel = currentLevel;
}
}
generateOutline();
CSS Debugging Techniques
Visualizing Layout
/* 1. Outline all elements */
* {
outline: 1px solid rgba(255, 0, 0, 0.1) !important;
background: rgba(0, 0, 0, 0.05) !important;
}
/* 2. Debug specific elements */
.debug {
outline: 2px solid red !important;
background: rgba(255, 0, 0, 0.1) !important;
}
/* 3. Show element margins */
* {
background: linear-gradient(90deg,
rgba(255, 0, 0, 0.2) 0%,
rgba(255, 0, 0, 0.2) 100%) !important;
}
/* 4. Show padding */
* {
background-clip: content-box !important;
background-color: rgba(0, 255, 0, 0.1) !important;
}
/* 5. Debug positioning */
.debug-position {
position: relative;
}
.debug-position::after {
content: attr(class);
position: absolute;
top: 0;
left: 0;
background: red;
color: white;
font-size: 12px;
z-index: 9999;
}
CSS Debugging Scripts
// CSS debugging utilities
// 1. Find unused CSS (simplified)
function findUnusedSelectors() {
const stylesheets = document.styleSheets;
const usedSelectors = new Set();
// Collect all elements
document.querySelectorAll('*').forEach(el => {
usedSelectors.add(el.tagName.toLowerCase());
if (el.id) usedSelectors.add(`#${el.id}`);
el.classList.forEach(cls => usedSelectors.add(`.${cls}`));
});
// Check stylesheets
for (const sheet of stylesheets) {
try {
const rules = sheet.cssRules;
for (const rule of rules) {
if (rule.selectorText) {
const selectors = rule.selectorText.split(',');
for (const selector of selectors) {
const trimmed = selector.trim();
if (!isSelectorUsed(trimmed, usedSelectors)) {
console.warn('Potentially unused:', trimmed);
}
}
}
}
} catch (e) {
// Cross-origin stylesheet
}
}
}
// 2. Check for invalid CSS properties
function validateCSSProperties(element) {
const styles = getComputedStyle(element);
const properties = [
'display', 'position', 'width', 'height',
'margin', 'padding', 'color', 'background'
];
properties.forEach(prop => {
const value = styles[prop];
if (value === '') {
console.warn(`${prop} not set on element:`, element);
}
});
}
// 3. Detect CSS animation performance issues
function detectCSSAnimations() {
const animated = document.querySelectorAll('*');
animated.forEach(el => {
const anim = getComputedStyle(el).animation;
if (anim !== 'none') {
console.log('Animated element:', el, anim);
}
});
}
Box Model Debugging
/* Box model debugging techniques */
/* 1. Box model visualization */
.debug-box {
box-sizing: border-box;
position: relative;
}
.debug-box::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 2px solid red;
pointer-events: none;
z-index: 9999;
}
/* 2. Show element dimensions */
.debug-dimensions::after {
content: attr(class) ' ' attr(id) ' ' attr(data-dimensions);
position: absolute;
top: 0;
left: 0;
background: black;
color: white;
font-size: 12px;
white-space: nowrap;
z-index: 10000;
}
/* 3. Detect overflow */
* {
overflow-x: auto;
resize: both;
}
/* 4. Debug flexbox */
.flex-container {
outline: 2px solid blue;
}
.flex-container > * {
outline: 1px solid rgba(0, 0, 255, 0.3);
}
/* 5. Debug grid */
.grid-container {
outline: 2px solid green;
position: relative;
}
.grid-container::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(90deg,
rgba(0, 255, 0, 0.1) 1px,
transparent 1px);
background-size: var(--grid-size, 20px) 100%;
pointer-events: none;
}
Specificity Debugging
// Specificity calculator
function calculateSpecificity(selector) {
let specificity = [0, 0, 0, 0]; // [inline, id, class, element]
// Count inline styles (simplified)
if (selector.includes('style')) {
specificity[0] = 1;
}
// Count IDs
const idCount = (selector.match(/#[a-zA-Z][\w-]*/g) || []).length;
specificity[1] = idCount;
// Count classes, attributes, pseudo-classes
const classCount = (selector.match(/\.[a-zA-Z][\w-]*/g) || []).length;
const attrCount = (selector.match(/\[[^\]]+\]/g) || []).length;
const pseudoCount = (selector.match(/:[a-z-]+(?!:)/g) || []).length;
specificity[2] = classCount + attrCount + pseudoCount;
// Count elements and pseudo-elements
const elementCount = (selector.match(/[a-z][a-z0-9]*/gi) || []).length;
const pseudoElementCount = (selector.match(/::[a-z-]+/g) || []).length;
specificity[3] = elementCount + pseudoElementCount;
return specificity;
}
// Debug a specific element
function debugElementSpecificity(element) {
const styles = window.getComputedStyle(element);
const classes = Array.from(element.classList);
console.group(`Debugging: ${element.tagName}.${classes.join('.')}`);
// Find applied rules
const sheets = document.styleSheets;
for (const sheet of sheets) {
try {
const rules = sheet.cssRules;
for (const rule of rules) {
if (rule.selectorText && element.matches(rule.selectorText)) {
const spec = calculateSpecificity(rule.selectorText);
console.log(`${spec.join(',')} - ${rule.selectorText}`, rule.style);
}
}
} catch (e) {}
}
console.groupEnd();
}
Layout Debugging
Flexbox Debugging
/* Flexbox debugging techniques */
/* 1. Visualize flex containers */
.flex-debug {
outline: 2px solid #e74c3c !important;
position: relative;
}
.flex-debug::before {
content: 'flex';
position: absolute;
top: -20px;
left: 0;
background: #e74c3c;
color: white;
padding: 2px 6px;
font-size: 12px;
font-family: monospace;
}
/* 2. Show flex item boundaries */
.flex-item-debug {
outline: 1px dashed #3498db !important;
position: relative;
}
.flex-item-debug::after {
content: 'item';
position: absolute;
bottom: 0;
right: 0;
background: #3498db;
color: white;
font-size: 10px;
padding: 2px 4px;
}
/* 3. Debug flex axes */
.flex-container {
background: linear-gradient(90deg,
rgba(231, 76, 60, 0.2) 0%,
rgba(231, 76, 60, 0.2) 1px,
transparent 1px);
background-size: 20px 100%;
}
/* 4. Debug alignment */
.flex-container {
position: relative;
}
.flex-container::after {
content: 'main axis →';
position: absolute;
bottom: -20px;
left: 0;
font-size: 12px;
color: #e74c3c;
}
Grid Debugging
/* Grid debugging techniques */
/* 1. Visualize grid lines */
.grid-debug {
outline: 2px solid #2ecc71 !important;
position: relative;
}
.grid-debug {
background: repeating-linear-gradient(
90deg,
rgba(46, 204, 113, 0.2) 0px,
rgba(46, 204, 113, 0.2) 1px,
transparent 1px,
transparent var(--grid-column-width, 20px)
);
}
/* 2. Show grid areas */
.grid-debug::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: repeating-linear-gradient(
0deg,
rgba(46, 204, 113, 0.2) 0px,
rgba(46, 204, 113, 0.2) 1px,
transparent 1px,
transparent var(--grid-row-height, 20px)
);
}
/* 3. Show item placement */
.grid-item-debug {
outline: 2px solid #f39c12 !important;
position: relative;
}
.grid-item-debug::after {
content: 'grid item';
position: absolute;
bottom: 0;
left: 0;
background: #f39c12;
color: white;
font-size: 10px;
padding: 2px 4px;
}
/* 4. Debug named lines */
.grid-with-named-lines {
grid-template-columns: [start] 1fr [center] 2fr [end];
}
Layout Overflow Debugging
/* Overflow debugging */
/* 1. Show overflow */
* {
overflow-x: auto;
overflow-y: visible;
}
/* 2. Highlight overflow content */
.debug-overflow {
overflow: auto;
position: relative;
}
.debug-overflow::after {
content: '⚠️ overflow';
position: absolute;
bottom: 0;
right: 0;
background: #e74c3c;
color: white;
font-size: 10px;
padding: 2px 4px;
z-index: 9999;
}
/* 3. Detect hidden overflow */
.detect-overflow {
overflow: hidden;
resize: both;
}
/* 4. Prevent overflow on all elements */
* {
max-width: 100%;
word-wrap: break-word;
}
Layout Debugging Scripts
// Layout debugging utilities
// 1. Detect element collisions
function detectCollisions(selector) {
const elements = document.querySelectorAll(selector);
const collisions = [];
for (let i = 0; i < elements.length; i++) {
const rect1 = elements[i].getBoundingClientRect();
for (let j = i + 1; j < elements.length; j++) {
const rect2 = elements[j].getBoundingClientRect();
if (rect1.right > rect2.left &&
rect1.left < rect2.right &&
rect1.bottom > rect2.top &&
rect1.top < rect2.bottom) {
collisions.push([elements[i], elements[j]]);
}
}
}
if (collisions.length) {
console.warn('Collisions found:', collisions.length);
collisions.forEach(([el1, el2]) => {
console.log(`${el1} collides with ${el2}`);
});
}
return collisions;
}
// 2. Check element visibility
function checkVisibility(selector) {
const elements = document.querySelectorAll(selector);
elements.forEach(el => {
const rect = el.getBoundingClientRect();
const styles = getComputedStyle(el);
const isVisible = rect.width > 0 &&
rect.height > 0 &&
styles.visibility !== 'hidden' &&
styles.opacity !== '0' &&
styles.display !== 'none';
if (!isVisible) {
console.warn('Element not visible:', el);
}
});
}
// 3. Measure layout shifts (CLS)
let clsScore = 0;
let sessionEntries = [];
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) {
clsScore += entry.value;
console.log('Layout shift:', entry.value);
}
}
}).observe({type: 'layout-shift', buffered: true});
// 4. Find elements outside viewport
function findOffscreenElements() {
const elements = document.querySelectorAll('*');
const offscreen = [];
elements.forEach(el => {
const rect = el.getBoundingClientRect();
if (rect.bottom < 0 || rect.top > window.innerHeight ||
rect.right < 0 || rect.left > window.innerWidth) {
offscreen.push(el);
}
});
console.log('Offscreen elements:', offscreen.length);
return offscreen;
}
Responsive Design Testing
Viewport Testing
<!-- Viewport testing meta tags -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Testing different viewport sizes -->
<script>
// Simulate different viewport sizes
function setViewportSize(width, height) {
window.resizeTo(width, height);
}
// Test common device sizes
const devices = {
'iPhone SE': { width: 375, height: 667 },
'iPhone 12': { width: 390, height: 844 },
'iPad': { width: 768, height: 1024 },
'iPad Pro': { width: 1024, height: 1366 },
'Desktop HD': { width: 1366, height: 768 },
'Desktop Full': { width: 1920, height: 1080 }
};
function testResponsive() {
for (const [name, size] of Object.entries(devices)) {
console.log(`Testing ${name} (${size.width}x${size.height})`);
setViewportSize(size.width, size.height);
// Wait and capture screenshot would go here
}
}
</script>
Media Query Testing
// Media query testing utilities
// 1. List active media queries
function listActiveMediaQueries() {
const stylesheets = document.styleSheets;
const activeQueries = [];
for (const sheet of stylesheets) {
try {
const rules = sheet.cssRules;
for (const rule of rules) {
if (rule.type === CSSRule.MEDIA_RULE) {
if (window.matchMedia(rule.conditionText).matches) {
activeQueries.push(rule.conditionText);
}
}
}
} catch (e) {}
}
console.log('Active media queries:', activeQueries);
return activeQueries;
}
// 2. Monitor viewport changes
function monitorViewport() {
const observer = new ResizeObserver(() => {
console.log(`Viewport: ${window.innerWidth}x${window.innerHeight}`);
// Check breakpoints
const breakpoints = {
'mobile': window.innerWidth < 768,
'tablet': window.innerWidth >= 768 && window.innerWidth < 1024,
'desktop': window.innerWidth >= 1024 && window.innerWidth < 1440,
'wide': window.innerWidth >= 1440
};
for (const [breakpoint, active] of Object.entries(breakpoints)) {
if (active) {
console.log(`Active breakpoint: ${breakpoint}`);
}
}
});
observer.observe(document.body);
}
// 3. Test element at different breakpoints
function testBreakpoints(element, properties) {
const breakpoints = [375, 768, 1024, 1440, 1920];
const results = {};
breakpoints.forEach(width => {
window.innerWidth = width;
window.dispatchEvent(new Event('resize'));
const styles = getComputedStyle(element);
results[width] = {};
properties.forEach(prop => {
results[width][prop] = styles[prop];
});
});
console.table(results);
return results;
}
Responsive Debugging Tools
/* Responsive debugging overlay */
/* 1. Device frame simulation */
@media (max-width: 768px) {
body::before {
content: 'Mobile View';
position: fixed;
top: 0;
left: 0;
right: 0;
background: #e74c3c;
color: white;
text-align: center;
padding: 4px;
font-size: 12px;
z-index: 9999;
}
}
@media (min-width: 769px) and (max-width: 1024px) {
body::before {
content: 'Tablet View';
background: #f39c12;
}
}
@media (min-width: 1025px) and (max-width: 1440px) {
body::before {
content: 'Desktop View';
background: #2ecc71;
}
}
@media (min-width: 1441px) {
body::before {
content: 'Wide Screen';
background: #3498db;
}
}
/* 2. Grid overlay for responsive testing */
.responsive-grid {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
z-index: 9998;
background: repeating-linear-gradient(
90deg,
rgba(0, 0, 0, 0.1) 0px,
rgba(0, 0, 0, 0.1) 1px,
transparent 1px,
transparent 8.333% /* 12 columns */
);
}
/* 3. Touch target debugging */
@media (hover: none) and (pointer: coarse) {
a, button, [role="button"] {
outline: 2px solid #e74c3c;
}
a:active, button:active {
background: rgba(231, 76, 60, 0.2);
}
}
Performance Debugging
Paint and Layout Debugging
// Performance debugging utilities
// 1. Monitor layout thrashing
let layoutCount = 0;
let paintCount = 0;
const layoutObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.entryType === 'layout-shift') {
layoutCount++;
console.warn('Layout shift detected:', entry);
}
}
});
layoutObserver.observe({entryTypes: ['layout-shift']});
// 2. Track forced reflows
function trackForcedReflows() {
const originalGetComputedStyle = window.getComputedStyle;
let reflowCount = 0;
window.getComputedStyle = function(...args) {
reflowCount++;
if (reflowCount % 100 === 0) {
console.warn(`Forced reflow #${reflowCount} detected`);
}
return originalGetComputedStyle.apply(this, args);
};
return () => {
console.log(`Total forced reflows: ${reflowCount}`);
window.getComputedStyle = originalGetComputedStyle;
};
}
// 3. Measure CSS selector performance
function measureSelectorPerformance(selector) {
const start = performance.now();
const elements = document.querySelectorAll(selector);
const end = performance.now();
console.log(`Selector "${selector}" took ${(end - start).toFixed(2)}ms`);
return elements.length;
}
// 4. Analyze critical rendering path
function analyzeCRP() {
const resources = performance.getEntriesByType('resource');
const cssResources = resources.filter(r =>
r.name.endsWith('.css') || r.initiatorType === 'link'
);
console.log('CSS Resources:', cssResources.length);
cssResources.forEach(css => {
console.log(`- ${css.name}: ${css.duration.toFixed(2)}ms`);
});
}
CSS Performance Debugging
/* CSS performance debugging */
/* 1. Identify expensive properties */
.expensive {
/* Expensive to paint */
box-shadow: 0 10px 20px rgba(0,0,0,0.2);
border-radius: 10px;
filter: blur(5px);
/* Expensive to layout */
float: left;
position: relative;
top: 10px;
/* Expensive to composite */
transform: translateZ(0);
opacity: 0.5;
}
/* 2. Use will-change sparingly */
.will-change {
will-change: transform; /* Only when necessary */
}
/* 3. Avoid layout thrashing */
.animate {
transform: translateX(100px); /* Good - uses compositor */
left: 100px; /* Bad - causes layout */
}
/* 4. Optimize animations */
@keyframes smooth {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(100px);
opacity: 0.5;
}
}
.smooth {
animation: smooth 0.3s;
will-change: transform, opacity;
}
JavaScript Performance Profiling
// Performance profiling
// 1. Time operations
console.time('DOM Manipulation');
// ... operations ...
console.timeEnd('DOM Manipulation');
// 2. Memory profiling
console.memory; // Check memory usage
// 3. Frame rate monitoring
let lastTimestamp = performance.now();
let frames = 0;
function checkFPS() {
const now = performance.now();
frames++;
if (now >= lastTimestamp + 1000) {
console.log(`FPS: ${frames}`);
frames = 0;
lastTimestamp = now;
}
requestAnimationFrame(checkFPS);
}
requestAnimationFrame(checkFPS);
// 4. Long task detection
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.duration > 50) {
console.warn(`Long task: ${entry.duration.toFixed(2)}ms`, entry);
}
}
});
observer.observe({entryTypes: ['longtask']});
Accessibility Testing
Manual Accessibility Checks
// Accessibility testing utilities
// 1. Check color contrast
function checkColorContrast(element) {
const styles = getComputedStyle(element);
const bgColor = styles.backgroundColor;
const textColor = styles.color;
function getLuminance(rgb) {
// Simplified luminance calculation
const r = rgb[0] / 255;
const g = rgb[1] / 255;
const b = rgb[2] / 255;
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
// Parse colors and calculate contrast ratio
console.log(`Element: ${element.tagName}`);
console.log(`Background: ${bgColor}`);
console.log(`Text: ${textColor}`);
}
// 2. Check heading order
function checkHeadingOrder() {
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
let currentLevel = 1;
headings.forEach(heading => {
const level = parseInt(heading.tagName[1]);
if (level > currentLevel + 1) {
console.warn(`Heading level skipped: h${currentLevel + 1} to h${level}`);
}
currentLevel = level;
});
}
// 3. Check image alt text
function checkAltText() {
const images = document.querySelectorAll('img');
const missingAlt = [];
images.forEach(img => {
if (!img.hasAttribute('alt')) {
missingAlt.push(img);
console.warn('Missing alt attribute:', img);
} else if (img.alt === '') {
console.log('Decorative image with empty alt:', img);
}
});
console.log(`Images without alt: ${missingAlt.length}`);
}
// 4. Check ARIA attributes
function checkARIA() {
const ariaElements = document.querySelectorAll('[aria-*]');
console.log(`Elements with ARIA: ${ariaElements.length}`);
ariaElements.forEach(el => {
const attributes = [...el.attributes].filter(attr =>
attr.name.startsWith('aria-')
);
console.log(`${el.tagName}:`, attributes.map(a => a.name));
});
}
Automated Accessibility Testing
<!-- Accessibility testing tools --> <!-- 1. Axe accessibility testing --> <script src="https://cdn.jsdelivr.net/npm/[email protected]/axe.min.js"></script> <script> axe.run().then(results => { console.log('Accessibility violations:', results.violations); results.violations.forEach(violation => { console.log(`${violation.impact}: ${violation.description}`); }); }); </script> <!-- 2. Lighthouse accessibility score --> <!-- Run Lighthouse in DevTools for full accessibility audit --> <!-- 3. WAVE evaluation --> <!-- Use WAVE browser extension for visual accessibility testing --> <!-- 4. NVDA/JAWS testing --> <!-- Test with actual screen readers -->
Accessibility Debugging Tools
/* Visual accessibility debugging */
/* 1. Focus indicator debugging */
*:focus {
outline: 4px solid #ff0000 !important;
outline-offset: 2px !important;
}
/* 2. Show skip links */
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: black;
color: white;
padding: 8px;
z-index: 100;
}
.skip-link:focus {
top: 0;
}
/* 3. Debug hidden content */
[aria-hidden="true"] {
outline: 2px solid red !important;
}
/* 4. Check color contrast (visual) */
.low-contrast {
filter: grayscale(1);
}
Cross-Browser Testing
Browser Compatibility Testing
// Browser detection and testing
// 1. Feature detection
function checkCSSFeatures() {
const features = {
grid: CSS.supports('display', 'grid'),
flexbox: CSS.supports('display', 'flex'),
'custom-properties': CSS.supports('--css', 'variables'),
'backdrop-filter': CSS.supports('backdrop-filter', 'blur(10px)'),
'position-sticky': CSS.supports('position', 'sticky'),
'aspect-ratio': CSS.supports('aspect-ratio', '16/9'),
'subgrid': CSS.supports('grid-template-columns', 'subgrid')
};
console.table(features);
return features;
}
// 2. Browser info
function getBrowserInfo() {
const ua = navigator.userAgent;
const info = {
userAgent: ua,
platform: navigator.platform,
vendor: navigator.vendor,
language: navigator.language,
cookies: navigator.cookieEnabled,
online: navigator.onLine
};
console.log(info);
return info;
}
// 3. Feature-specific fallbacks
if (!CSS.supports('display', 'grid')) {
// Load flexbox fallback
loadStylesheet('fallback-grid.css');
}
function loadStylesheet(href) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = href;
document.head.appendChild(link);
}
Vendor Prefix Testing
/* Testing vendor prefixes */
/* 1. Cross-browser testing styles */
.element {
/* Modern syntax */
backdrop-filter: blur(10px);
/* Vendor prefixes */
-webkit-backdrop-filter: blur(10px);
-moz-backdrop-filter: blur(10px);
}
/* 2. Autoprefixer testing */
/* Check if autoprefixer is working correctly */
@supports (display: grid) {
.grid {
display: grid;
}
}
/* 3. Fallback testing */
.grid-container {
/* Fallback for old browsers */
display: block;
/* Modern syntax */
display: grid;
}
Validation Tools
HTML Validation
<!-- HTML validation tools -->
<!-- 1. W3C Validator -->
<!-- Use online validator: https://validator.w3.org/ -->
<!-- 2. Validate local HTML -->
<script>
function validateHTML() {
const html = document.documentElement.outerHTML;
// Send to validation API or use local tools
console.log('HTML length:', html.length);
}
</script>
<!-- 3. Check for common HTML errors -->
<script>
function checkHTMLErrors() {
const errors = [];
// Check for missing DOCTYPE
if (!document.doctype) {
errors.push('Missing DOCTYPE');
}
// Check for duplicate IDs
const ids = [...document.querySelectorAll('[id]')].map(el => el.id);
const duplicates = ids.filter((id, index) => ids.indexOf(id) !== index);
if (duplicates.length) {
errors.push(`Duplicate IDs: ${[...new Set(duplicates)]}`);
}
// Check for invalid nesting
document.querySelectorAll('ul > div, ol > div').forEach(el => {
errors.push(`Invalid nesting: ${el.tagName} inside list`);
});
console.log('HTML errors:', errors);
}
</script>
CSS Validation
/* CSS validation techniques */
/* 1. Check for invalid properties */
.invalid-property {
/* These will be flagged by CSS validators */
background-color: #rrggbb; /* Invalid color */
width: "100%"; /* Invalid quotes */
display: inline-flex-box; /* Invalid value */
}
/* 2. CSS validator tools */
/* - W3C CSS Validator: https://jigsaw.w3.org/css-validator/ */
/* - Stylelint for local validation */
/* 3. Stylelint configuration */
/* .stylelintrc.json */
{
"rules": {
"color-no-invalid-hex": true,
"declaration-block-no-duplicate-properties": true,
"selector-max-id": 0,
"unit-no-unknown": true
}
}
Custom Validation Scripts
// Custom validation scripts
// 1. CSS parser validation
function validateCSS() {
const stylesheets = document.styleSheets;
const warnings = [];
for (const sheet of stylesheets) {
try {
const rules = sheet.cssRules;
for (const rule of rules) {
// Check for duplicate properties
const properties = new Set();
for (let i = 0; i < rule.style.length; i++) {
const prop = rule.style[i];
if (properties.has(prop)) {
warnings.push(`Duplicate property "${prop}" in ${rule.selectorText}`);
}
properties.add(prop);
}
// Check for invalid values
if (rule.style.color === '#rrggbb') {
warnings.push(`Invalid color in ${rule.selectorText}`);
}
}
} catch (e) {
// Cross-origin stylesheet
}
}
console.log('CSS warnings:', warnings);
return warnings;
}
// 2. HTML structure validation
function validateHTMLStructure() {
const issues = [];
// Check document has exactly one h1
const h1Count = document.querySelectorAll('h1').length;
if (h1Count === 0) {
issues.push('No h1 element found');
} else if (h1Count > 1) {
issues.push(`Multiple h1 elements (${h1Count})`);
}
// Check for empty links
document.querySelectorAll('a:empty').forEach(el => {
issues.push(`Empty link: ${el.outerHTML}`);
});
// Check for orphaned labels
document.querySelectorAll('label[for]').forEach(label => {
const forId = label.getAttribute('for');
if (!document.getElementById(forId)) {
issues.push(`Label references missing ID: ${forId}`);
}
});
return issues;
}
Automated Testing
Jest Testing for DOM
// Jest tests for DOM and CSS
// Install: npm install --save-dev jest jest-environment-jsdom
// Example test file: component.test.js
const fs = require('fs');
const path = require('path');
// Load HTML
const html = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf8');
describe('HTML Structure', () => {
beforeEach(() => {
document.body.innerHTML = html;
});
test('Page has h1 heading', () => {
const h1 = document.querySelector('h1');
expect(h1).toBeTruthy();
expect(h1.textContent).toBeTruthy();
});
test('Navigation has correct links', () => {
const links = document.querySelectorAll('nav a');
expect(links.length).toBeGreaterThan(0);
links.forEach(link => {
expect(link.getAttribute('href')).toBeTruthy();
});
});
});
// CSS Testing with jest-styled-components
import { render } from '@testing-library/react';
import styled from 'styled-components';
const Button = styled.button`
background: ${props => props.primary ? 'blue' : 'gray'};
color: white;
padding: 10px 20px;
`;
test('Button has correct styles', () => {
const { container } = render(<Button primary />);
const button = container.firstChild;
const styles = getComputedStyle(button);
expect(styles.backgroundColor).toBe('rgb(0, 0, 255)');
expect(styles.color).toBe('rgb(255, 255, 255)');
});
Cypress Testing
// Cypress E2E tests
// Install: npm install --save-dev cypress
// cypress/e2e/layout.cy.js
describe('Layout Tests', () => {
beforeEach(() => {
cy.visit('/');
});
it('Responsive navigation works', () => {
// Mobile viewport
cy.viewport('iphone-6');
cy.get('.mobile-menu').should('be.visible');
cy.get('.desktop-menu').should('not.be.visible');
// Desktop viewport
cy.viewport(1280, 720);
cy.get('.desktop-menu').should('be.visible');
cy.get('.mobile-menu').should('not.be.visible');
});
it('CSS Grid layout is correct', () => {
cy.get('.grid-container').should('have.css', 'display', 'grid');
cy.get('.grid-item').should('have.length.at.least', 1);
});
it('Form validation works', () => {
cy.get('form').within(() => {
cy.get('input[type="submit"]').click();
cy.get('.error-message').should('be.visible');
cy.get('#email').type('invalid');
cy.get('input[type="submit"]').click();
cy.get('.error-message').should('contain', 'valid email');
cy.get('#email').clear().type('[email protected]');
cy.get('input[type="submit"]').click();
cy.get('.success-message').should('be.visible');
});
});
});
Puppeteer Visual Regression
// Puppeteer visual regression testing
// Install: npm install --save-dev puppeteer jest-image-snapshot
const puppeteer = require('puppeteer');
const { toMatchImageSnapshot } = require('jest-image-snapshot');
expect.extend({ toMatchImageSnapshot });
describe('Visual Regression Tests', () => {
let browser;
let page;
beforeAll(async () => {
browser = await puppeteer.launch();
page = await browser.newPage();
await page.setViewport({ width: 1280, height: 720 });
});
afterAll(async () => {
await browser.close();
});
test('Home page matches snapshot', async () => {
await page.goto('http://localhost:3000');
const screenshot = await page.screenshot();
expect(screenshot).toMatchImageSnapshot();
});
test('Responsive layout on mobile', async () => {
await page.setViewport({ width: 375, height: 667 });
await page.goto('http://localhost:3000');
const screenshot = await page.screenshot();
expect(screenshot).toMatchImageSnapshot({
customSnapshotIdentifier: 'home-mobile'
});
});
test('Hover states are correct', async () => {
await page.goto('http://localhost:3000');
await page.hover('.button-primary');
const screenshot = await page.screenshot();
expect(screenshot).toMatchImageSnapshot({
customSnapshotIdentifier: 'button-hover'
});
});
});
Debugging Workflows
Systematic Debugging Approach
// Structured debugging workflow
// 1. Reproduce the issue
function reproduceIssue() {
console.group('Reproduction Steps');
console.log('1. Navigate to page');
console.log('2. Click on element');
console.log('3. Observe issue');
console.groupEnd();
}
// 2. Isolate the issue
function isolateIssue(selector) {
// Remove other elements temporarily
const parent = document.querySelector(selector).parentElement;
const siblings = [...parent.children];
siblings.forEach(sibling => {
if (sibling !== document.querySelector(selector)) {
sibling.style.display = 'none';
}
});
console.log('Isolated element:', selector);
}
// 3. Create minimal test case
function createMinimalTestCase() {
const html = document.documentElement.outerHTML;
console.log('Minimal HTML:', html);
// Create sandbox link
const sandboxLink = 'https://jsbin.com/?html,' + encodeURIComponent(html);
console.log('Test in sandbox:', sandboxLink);
}
// 4. Check browser compatibility
function checkBrowserCompatibility() {
const userAgent = navigator.userAgent;
console.log('Browser:', userAgent);
// Test for known issues
const issues = [];
if (userAgent.includes('Trident')) {
issues.push('Internet Explorer detected - check flexbox/grid support');
}
if (userAgent.includes('Edge/1')) {
issues.push('Edge Legacy detected - check CSS variables');
}
if (userAgent.includes('Firefox')) {
issues.push('Firefox detected - check scrollbar styling');
}
issues.forEach(issue => console.warn(issue));
}
Debugging Checklist
// Comprehensive debugging checklist
function debuggingChecklist() {
const checks = {
// HTML structure
html: [
'DOCTYPE present',
'Meta charset defined',
'Viewport meta tag',
'Semantic HTML used',
'No duplicate IDs',
'Proper heading hierarchy'
],
// CSS styles
css: [
'Specificity conflicts',
'!important usage',
'Invalid properties',
'Missing fallbacks',
'Responsive breakpoints',
'Print styles'
],
// Layout
layout: [
'Box model correct',
'No unexpected overflow',
'Flexbox/grid properties',
'Positioning correct',
'Z-index stacking',
'Float clearing'
],
// Responsive
responsive: [
'Mobile viewport',
'Tablet breakpoints',
'Desktop breakpoints',
'Touch targets size',
'Images scale properly',
'Text readable at all sizes'
],
// Performance
performance: [
'CSS minified',
'Critical CSS inlined',
'No unused CSS',
'No render-blocking CSS',
'Image optimization',
'Font loading optimized'
],
// Accessibility
accessibility: [
'Alt text for images',
'Focus indicators visible',
'Color contrast sufficient',
'ARIA labels where needed',
'Keyboard navigation',
'Screen reader testing'
],
// Browser compatibility
compatibility: [
'Feature detection used',
'Vendor prefixes present',
'Fallbacks for older browsers',
'CSS Grid fallback',
'Flexbox fallback',
'Font fallbacks'
]
};
for (const [category, items] of Object.entries(checks)) {
console.group(`📋 ${category.toUpperCase()} Checklist`);
items.forEach(item => {
console.log(`[ ] ${item}`);
});
console.groupEnd();
}
}
Common Issues and Solutions
Layout Issues
/* Common layout issues and fixes */
/* Issue 1: Unexpected overflow */
.overflow-issue {
width: 100%;
padding: 20px; /* This causes overflow! */
}
/* Fix 1: Use box-sizing */
.fix-overflow {
box-sizing: border-box;
width: 100%;
padding: 20px;
}
/* Issue 2: Float clearing */
.float-container {
overflow: hidden; /* Creates new block formatting context */
display: flow-root; /* Modern solution */
}
.float-container::after {
content: '';
display: table;
clear: both;
}
/* Issue 3: Flexbox wrapping */
.flex-wrap-issue {
display: flex;
flex-wrap: wrap;
}
.flex-wrap-issue > * {
flex: 1 1 200px; /* Prevents squishing */
min-width: 0; /* Prevents overflow */
}
/* Issue 4: Grid gaps */
.grid-gap-issue {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
/* Fix for older browsers */
.grid-gap-fallback {
display: flex;
margin: -10px;
}
.grid-gap-fallback > * {
margin: 10px;
flex: 1 1 0;
}
Specificity Issues
/* Specificity issues and solutions */
/* Issue 1: !important overuse */
.important-overuse {
color: red !important; /* Avoid this */
}
/* Solution: Increase specificity */
.parent .component {
color: red; /* More specific */
}
/* Issue 2: ID selector overrides */
#id-selector {
color: blue;
}
.component {
color: red; /* Won't override ID */
}
/* Solution: Use more specific class */
.component-id {
color: red;
}
/* Issue 3: Inline styles overriding */
/* Bad */
<div style="color: blue;">Text</div>
/* Good */
<div class="dynamic-color">Text</div>
.dynamic-color {
color: var(--text-color);
}
Responsive Issues
/* Responsive design issues */
/* Issue 1: Fixed widths on mobile */
.fixed-width {
width: 800px; /* Too wide for mobile */
}
/* Solution: Responsive widths */
.responsive-width {
width: 100%;
max-width: 800px;
}
/* Issue 2: Images that don't scale */
.fixed-image {
width: 800px; /* Overflows on mobile */
}
/* Solution: Responsive images */
.responsive-image {
max-width: 100%;
height: auto;
}
/* Issue 3: Font sizes too small */
.small-text {
font-size: 12px; /* Too small on mobile */
}
/* Solution: Responsive typography */
.responsive-text {
font-size: clamp(14px, 4vw, 18px);
}
/* Issue 4: Touch targets too small */
.small-target {
width: 20px;
height: 20px; /* Hard to tap */
}
/* Solution: Minimum touch target size */
.touch-target {
min-width: 44px;
min-height: 44px;
}
Performance Issues
/* Performance issues and solutions */
/* Issue 1: Expensive selectors */
* > * > * > .deep {
/* Very expensive */
}
/* Solution: Simplified selectors */
.component {
/* Much faster */
}
/* Issue 2: Animation on layout properties */
@keyframes bad {
to {
left: 100px; /* Causes layout recalc */
width: 200px; /* Causes layout recalc */
}
}
/* Solution: Animate compositor properties */
@keyframes good {
to {
transform: translateX(100px);
opacity: 0.5;
}
}
/* Issue 3: Too many fonts */
@font-face {
font-family: 'Custom';
src: url('custom.woff2');
/* Each font adds weight */
}
/* Solution: System fonts */
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
/* Issue 4: Large CSS files */
/* Solution: Code splitting */
<link rel="preload" href="critical.css" as="style">
<link rel="stylesheet" href="critical.css">
<link rel="preload" href="non-critical.css" as="style" media="print">
Best Practices
Debugging Best Practices
// Debugging best practices
// 1. Always reproduce issues consistently
function reproduceIssue() {
// Document steps
const steps = [
'Open page at URL',
'Resize to 768px',
'Click menu button',
'Observe layout shift'
];
console.table(steps);
}
// 2. Isolate the problem
function isolateProblem(element) {
// Remove other elements temporarily
const clone = element.cloneNode(true);
document.body.innerHTML = '';
document.body.appendChild(clone);
// Test with minimal environment
console.log('Isolated element:', element);
}
// 3. Use browser DevTools effectively
function useDevTools() {
console.log('DevTools shortcuts:');
console.log(' Elements: Cmd/Ctrl + Shift + C');
console.log(' Console: Cmd/Ctrl + Shift + J');
console.log(' Performance: Cmd/Ctrl + Shift + E');
console.log(' Device mode: Cmd/Ctrl + Shift + M');
}
// 4. Check the cascade
function checkCascade(element) {
const styles = getComputedStyle(element);
const importantProps = [];
for (const prop of styles) {
const value = styles.getPropertyValue(prop);
const priority = styles.getPropertyPriority(prop);
if (priority === 'important') {
importantProps.push(prop);
}
}
if (importantProps.length) {
console.warn('!important properties:', importantProps);
}
}
Testing Best Practices
// Testing best practices
// 1. Test on real devices
function testDevices() {
const devices = [
'iPhone SE',
'iPhone 12',
'iPad',
'Pixel 5',
'Galaxy S20',
'Desktop Chrome',
'Desktop Firefox',
'Desktop Safari'
];
console.log('Test on:', devices.join(', '));
}
// 2. Use browser emulation
function emulateDevice(device) {
const emulations = {
'iPhone SE': { width: 375, height: 667, deviceScaleFactor: 2 },
'iPad': { width: 768, height: 1024, deviceScaleFactor: 2 },
'Desktop': { width: 1280, height: 720, deviceScaleFactor: 1 }
};
const settings = emulations[device];
if (settings) {
console.log(`Emulating ${device}: ${settings.width}x${settings.height}`);
}
}
// 3. Automate regression testing
function regressionTest() {
const screenshots = [];
const breakpoints = [320, 768, 1024, 1440];
breakpoints.forEach(width => {
window.innerWidth = width;
window.dispatchEvent(new Event('resize'));
// Take screenshot would go here
screenshots.push({ width, element: document.body });
});
console.log('Regression test complete');
}
Code Quality Best Practices
/* Code quality best practices */
/* 1. Comment your code */
/*
* Navigation component
* Fixed header with responsive mobile menu
* Uses flexbox for alignment
*/
.nav {
display: flex;
justify-content: space-between;
align-items: center;
}
/* 2. Use consistent naming */
/* BEM naming convention */
.card { }
.card__title { }
.card__image { }
.card__button { }
.card__button--primary { }
/* 3. Group related styles */
/* Layout styles */
.container { }
.grid { }
/* Component styles */
.button { }
.card { }
/* Utility styles */
.text-center { }
.hidden { }
/* 4. Use CSS custom properties */
:root {
/* Colors */
--color-primary: #3498db;
/* Spacing */
--spacing-unit: 8px;
/* Typography */
--font-size-base: 16px;
}
/* 5. Avoid !important */
/* Bad */
.button {
color: red !important;
}
/* Good */
.special-button {
color: red;
}
Performance Best Practices
/* Performance best practices */
/* 1. Use CSS containment */
.component {
contain: layout style paint; /* Improves rendering */
}
/* 2. Optimize animations */
.animated {
will-change: transform;
transform: translateZ(0); /* Creates new layer */
}
/* 3. Use CSS Grid for layout */
/* Better than nested floats or complex flexbox */
.layout {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 20px;
}
/* 4. Minimize repaints */
/* Bad */
.hover-effect {
transition: width 0.3s;
}
/* Good */
.hover-effect {
transition: transform 0.3s;
}
/* 5. Use font-display */
@font-face {
font-family: 'Custom';
src: url('custom.woff2');
font-display: swap; /* Shows fallback while loading */
}
Conclusion
Debugging and testing HTML and CSS are essential skills for every web developer. This comprehensive guide covered:
Key Takeaways
- Browser DevTools are your primary debugging tool
- Systematic approach to debugging saves time
- Visual debugging techniques help identify layout issues
- Performance profiling ensures smooth experiences
- Accessibility testing makes sites usable for everyone
- Cross-browser testing ensures compatibility
- Automated testing catches regressions early
- Validation tools catch syntax and structure issues
Debugging Checklist
- [ ] Reproduce the issue consistently
- [ ] Isolate the problem area
- [ ] Use browser DevTools to inspect
- [ ] Check HTML structure
- [ ] Analyze CSS cascade
- [ ] Verify box model calculations
- [ ] Test responsive breakpoints
- [ ] Measure performance impact
- [ ] Validate accessibility
- [ ] Test cross-browser compatibility
- [ ] Create minimal test case
- [ ] Document solution
Tools Reference
| Tool | Purpose | Link |
|---|---|---|
| Chrome DevTools | Primary debugging | Built-in |
| W3C Validator | HTML/CSS validation | validator.w3.org |
| Lighthouse | Performance/accessibility | Built-in |
| Axe | Accessibility testing | deque.com/axe |
| Stylelint | CSS linting | stylelint.io |
| Jest | DOM testing | jestjs.io |
| Cypress | E2E testing | cypress.io |
| Puppeteer | Visual regression | pptr.dev |
Remember: The best debugger is a good understanding of how HTML, CSS, and the browser work together. Practice these techniques regularly, and you'll become proficient at identifying and fixing issues quickly!
HTML & CSS Learning Guides, Exercises, Projects, Design Systems, Accessibility & Performance (Related to HTML & CSS Development)
HTML & CSS Quiz – Comprehensive Assessment:
This quiz evaluates core knowledge of HTML and CSS including structure, styling, layout, forms, and responsive design. It is used to test practical understanding of front-end fundamentals and identify skill levels in web development.
Read more: https://macronepal.com/bash/html-and-css-quiz-comprehensive-assessment/
Complete Guide to HTML & CSS Tooling & Automation:
This guide explains tools and automation workflows used in modern web development, such as preprocessors, build tools, and task runners that improve efficiency in HTML and CSS projects.
Read more: https://macronepal.com/bash/complete-guide-to-html-and-css-tooling-automation/
Complete HTML & CSS Exercises:
A collection of practical exercises designed to strengthen HTML and CSS skills through hands-on coding tasks, covering layout, styling, and responsive design concepts.
Read more: https://macronepal.com/bash/complete-html-and-css-exercises/
Complete HTML & CSS Landing Page Project:
This project focuses on building a full landing page using HTML and CSS, helping learners understand real-world website structure, layout design, and UI development.
Read more: https://macronepal.com/bash/complete-html-css-landing-page-project/
HTML & CSS Debugging and Testing Guide:
This guide teaches how to identify and fix errors in HTML and CSS code, along with testing techniques to ensure websites work correctly across browsers.
Read more: https://macronepal.com/bash/complete-guide-to-html-and-css-debugging-testing/
HTML & CSS Design Systems Guide:
A design system approach helps maintain consistency in UI development using reusable components, styles, and patterns across web projects.
Read more: https://macronepal.com/html-and-css/complete-guide-to-html-and-css-design-systems/
HTML & CSS Accessibility (A11y) Guide:
This guide focuses on making websites accessible for all users, including proper semantic HTML, keyboard navigation, alt text, and screen reader support.
Read more: https://macronepal.com/bash/complete-guide-to-html-css-accessibility-a11y/
HTML & CSS Performance Guide:
This topic explains optimization techniques such as reducing file size, improving loading speed, and writing efficient HTML and CSS for better website performance.
Read more: https://macronepal.com/bash/complete-guide-to-html-and-css-performance/
HTML & CSS Design Systems (Advanced Overview):
Design systems help developers maintain scalable and consistent UI components across large projects using structured HTML and reusable CSS patterns.
Read more: https://macronepal.com/html-and-css/complete-guide-to-html-and-css-design-systems/