Photo by Rahul Mishra on Unsplash
Card Neo Brutalism Design Using HTML, CSS, and JavaScript
Create a modern, responsive card design in the neo-brutalist style using HTML, CSS, and JavaScript, featuring bold colors, thick borders, and heavy shadows for a raw, unpolished aesthetic. This implementation focuses on striking visuals, accessible interactions, and maintainable code, ideal for showcasing content in web interfaces.
Primary Card
A bold, neo-brutalist card for showcasing content with a raw aesthetic.
Secondary Card
This card uses an accent color for variety in the neo-brutalist style.
Prerequisites
- Basic HTML, CSS, and JavaScript knowledge
- A code editor (e.g., VS Code)
Part 1: Card Neo Brutalism Design
Step 1: HTML Structure (index.html)
Create a semantic HTML structure for the neo-brutalist cards with a container, image, title, content, and button.
<div class="card-container" role="group" aria-label="Neo-brutalist cards">
<div class="card" tabindex="0" aria-label="Primary card">
<img src="https://images.unsplash.com/photo-1506748686214-e9df14d4d9d0?q=80&w=1470&auto=format&fit=crop" alt="Abstract background" class="card-image">
<h2 class="card-title">Primary Card</h2>
<p class="card-content">A bold, neo-brutalist card for showcasing content with a raw aesthetic.</p>
<button class="card-button" aria-label="View primary card details">View Details</button>
</div>
<div class="card secondary" tabindex="0" aria-label="Secondary card">
<img src="https://images.unsplash.com/photo-1519125323398-675f0ddb6308?q=80&w=1470&auto=format&fit=crop" alt="Colorful abstract" class="card-image">
<h2 class="card-title">Secondary Card</h2>
<p class="card-content">This card uses an accent color for variety in the neo-brutalist style.</p>
<button class="card-button" aria-label="View secondary card details">View Details</button>
</div>
</div>
Step 2: Core CSS Implementation (styles.css)
Style the cards and their elements with neo-brutalist aesthetics: bold colors, thick borders, heavy shadows, and a monospace font.
:root {
--gray-900: #111827;
--gray-700: #374151;
--gray-200: #e5e7eb;
--gray-100: #f3f4f6;
--white: #ffffff;
--primary-600: #2563eb;
--primary-500: #3b82f6;
--accent-500: #f59e0b;
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 12px;
--spacing-lg: 16px;
--radius-sm: 4px;
--radius-md: 6px;
--transition: 0.2s ease;
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--shadow-neo: 6px 6px 0 var(--gray-900);
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--font-mono: 'IBM Plex Mono', monospace;
}
.card-container {
display: flex;
gap: var(--spacing-md);
background: var(--white);
padding: var(--spacing-lg);
border-radius: var(--radius-md);
box-shadow: var(--shadow-md);
flex-wrap: wrap;
justify-content: center;
}
.card {
background: var(--white);
border: 4px solid var(--gray-900);
border-radius: var(--radius-sm);
box-shadow: var(--shadow-neo);
width: 250px;
padding: var(--spacing-md);
font-family: var(--font-mono);
transition: transform var(--transition), box-shadow var(--transition);
cursor: pointer;
position: relative;
overflow: hidden;
}
.card:hover, .card.active {
transform: translate(3px, 3px);
box-shadow: 3px 3px 0 var(--gray-900);
}
.card:focus {
outline: none;
box-shadow: 3px 3px 0 var(--accent-500), 0 0 0 3px var(--primary-600);
}
.card.secondary {
border-color: var(--accent-500);
}
.card.secondary:focus {
box-shadow: 3px 3px 0 var(--primary-500), 0 0 0 3px var(--accent-500);
}
.card-image {
width: 100%;
height: 120px;
object-fit: cover;
border-bottom: 3px solid var(--gray-900);
margin-bottom: var(--spacing-sm);
}
.card-title {
font-size: 1.125rem;
font-weight: 600;
text-transform: uppercase;
color: var(--gray-900);
margin-bottom: var(--spacing-sm);
}
.card-content {
font-size: 0.875rem;
color: var(--gray-700);
margin-bottom: var(--spacing-md);
}
.card-button {
padding: var(--spacing-sm) var(--spacing-md);
font-family: var(--font-mono);
font-size: 0.875rem;
font-weight: 600;
text-transform: uppercase;
color: var(--gray-900);
background: var(--primary-500);
border: 3px solid var(--gray-900);
border-radius: var(--radius-sm);
box-shadow: var(--shadow-neo);
transition: transform var(--transition), box-shadow var(--transition);
cursor: pointer;
width: 100%;
text-align: center;
}
.card-button:hover {
transform: translate(2px, 2px);
box-shadow: 2px 2px 0 var(--gray-900);
}
.card-button:focus {
outline: none;
box-shadow: 2px 2px 0 var(--accent-500), 0 0 0 3px var(--primary-600);
}
.card.secondary .card-button {
background: var(--accent-500);
}
@media (max-width: 640px) {
.card-container {
flex-direction: column;
padding: var(--spacing-md);
gap: var(--spacing-sm);
}
.card {
width: 100%;
padding: var(--spacing-sm);
}
.card-image {
height: 100px;
}
.card-title {
font-size: 1rem;
}
.card-content {
font-size: 0.75rem;
}
.card-button {
font-size: 0.75rem;
}
}
Step 3: JavaScript Implementation (script.js)
Add JavaScript to manage card interactions, providing visual feedback for hover and focus states, and supporting keyboard accessibility.
document.addEventListener('DOMContentLoaded', () => {
const cards = document.querySelectorAll('.card');
const buttons = document.querySelectorAll('.card-button');
cards.forEach(card => {
// Add active class on hover or focus
card.addEventListener('mouseenter', () => {
card.classList.add('active');
});
card.addEventListener('mouseleave', () => {
card.classList.remove('active');
});
card.addEventListener('focus', () => {
card.classList.add('active');
});
card.addEventListener('blur', () => {
card.classList.remove('active');
});
// Keyboard support for Enter/Space to activate button
card.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
card.querySelector('.card-button').click();
}
});
});
// Simulate button click action (demo)
buttons.forEach(button => {
button.addEventListener('click', () => {
alert('Card button clicked! (Demo action)');
});
});
});
Explanation
- Layout: Cards are housed in a flexbox container with a white background, shadow, and rounded corners. Each card includes an image, title, content, and button, structured for clarity and visual hierarchy.
- Styling: Cards use a white background with thick black borders (
4px) or orange (--accent-500for secondary), offset shadows (--shadow-neo), and a monospace font. Buttons use blue (--primary-500) or orange, with matching borders and shadows. Images have a bold border-bottom for separation. - Interactivity: JavaScript adds an `active` class on hover or focus for cards, syncing with CSS for transform and shadow changes. Buttons trigger a demo alert on click. Keyboard support allows Enter/Space to activate the button.
- Visual Feedback: Hovering or focusing shifts cards (
translate(3px, 3px)) with reduced shadows; buttons shift slightly on hover (translate(2px, 2px)). Focus states add a dual shadow (accent and primary) for accessibility. - Responsiveness: A media query (
@media (max-width: 640px)) switches the container to a column layout, scales cards to full width, and reduces image height and font sizes for mobile usability. - Accessibility:
role="group"andaria-labelon the container, plusaria-labelandtabindex="0"on cards and buttons, ensure screen reader compatibility. Keyboard support (Tab, Enter, Space) and high contrast ratios (4.5:1 minimum) enhance usability. The monospace font is bold and readable.
Accessibility Features
- Use
role="group",aria-label, andtabindexfor semantic structure - Ensure high contrast ratios for text, borders, and backgrounds (4.5:1 minimum)
- Support keyboard navigation with Tab, Enter, and Space keys
- Use bold, readable typography (monospace for neo-brutalism)
Golden Rules
- Use CSS variables for consistent theming
- Implement bold borders and heavy shadows for neo-brutalist style
- Ensure accessibility with ARIA and keyboard support
- Optimize for mobile with responsive design
Conclusion
A professional neo-brutalist card should embrace raw, bold aesthetics, provide clear user interactions, remain responsive, and follow accessibility guidelines. This solution uses HTML, CSS, and JavaScript for striking cards with primary and secondary variants, featuring heavy shadows and a monospace font. Experiment with colors, shadow offsets, or add features like links or dynamic data. Test across devices and browsers for usability. Feel free to leave comments with any questions or suggestions!
Comments
Post a Comment