I asked Claude about whether or not we should now completely drop our Bootstrap 3.3.6 dependency given our recent design-tokens.css refactor. Response: https://claude.ai/share/6ae8d3a1-461e-45ff-84e7-cbdd2efe2dd5
Bootstrap Migration Analysis: Makeability Lab Website
Date: January 2, 2026
Current Stack: Bootstrap 3.3.6 + jQuery 1.9.1
Recommendation: Drop Bootstrap, go fully custom with vanilla CSS/JS
Executive Summary
The Makeability Lab website has evolved to the point where Bootstrap is more burden than benefit. With design-tokens.css and modern CSS (flexbox/grid) already powering the newer components, you're essentially maintaining two styling systems. Removing Bootstrap eliminates ~200KB of overridden CSS/JS, removes jQuery security concerns, and simplifies the codebase.
Current Bootstrap Usage Analysis
Component Inventory
| Component |
Usage Count |
Current State |
| Grid system |
~242 instances |
Mixed - newer pages use CSS Grid |
| Navbar |
1 (responsive collapse) |
Works but dated |
| Carousel |
2 (hero + project pages) |
Functional |
| Popover |
Citations only |
Already has custom JS wrapper |
| ScrollSpy |
Publications TOC |
Single use |
| Responsive utilities |
~30 (hidden-xs, etc.) |
Trivial to replace |
Grid Class Distribution
col-md-* : Most common (main layouts)
col-xs-* : Mobile overrides
col-sm-* : Tablet breakpoints
col-lg-* : Large screen tweaks
container : Page wrappers
row : Grid rows
JavaScript Dependencies
// Bootstrap JS components in use:
$('.carousel').carousel(); // Hero banners
$(trigger).popover('toggle'); // Citations
data-spy="scroll" // Publications TOC
data-toggle="collapse" // Mobile navbar
Why NOT Upgrade to Bootstrap 5
| Factor |
Bootstrap 3 → 5 Migration |
Drop Bootstrap Entirely |
| Class name changes |
Extensive (col-xs-* → col-*) |
One-time replacement |
| JS rewrite |
Still needed (new API) |
Already have custom code |
| Bundle size |
~150KB CSS + JS |
0KB added |
| jQuery |
Can drop, but new learning curve |
Already removing |
| Long-term maintenance |
Still external dependency |
Full control |
Verdict: Migration effort is similar, but dropping Bootstrap yields better long-term outcomes.
Migration Strategy
Phase 1: Remove jQuery (Week 1)
Risk: Low | Impact: High
jQuery 1.9.1 (2013) has known security vulnerabilities. Replace with vanilla JS.
// Before
$('.carousel').carousel();
$('.navbar-toggle').on('click', function() { ... });
// After
document.querySelector('.carousel'); // CSS handles transitions
document.querySelector('.navbar-toggle').addEventListener('click', ...);
Files to update:
website/templates/website/base.html (remove jQuery script tag)
website/static/website/js/top-navbar.js
website/static/website/js/citationPopoverSimple.js
Phase 2: Replace Bootstrap JS Components (Week 1-2)
Navbar Toggle (~20 lines)
// static/website/js/navbar.js
const NavbarToggle = (function() {
'use strict';
function init() {
const toggle = document.querySelector('.navbar-toggle');
const collapse = document.querySelector('.navbar-collapse');
if (!toggle || !collapse) return;
toggle.addEventListener('click', () => {
const isExpanded = toggle.getAttribute('aria-expanded') === 'true';
toggle.setAttribute('aria-expanded', !isExpanded);
collapse.classList.toggle('in');
});
// Close on outside click
document.addEventListener('click', (e) => {
if (!e.target.closest('.navbar') && collapse.classList.contains('in')) {
collapse.classList.remove('in');
toggle.setAttribute('aria-expanded', 'false');
}
});
}
return { init };
})();
document.addEventListener('DOMContentLoaded', NavbarToggle.init);
Carousel (~60 lines)
// static/website/js/carousel.js
const Carousel = (function() {
'use strict';
function init(selector, options = {}) {
const carousel = document.querySelector(selector);
if (!carousel) return;
const slides = carousel.querySelectorAll('.carousel-item');
const indicators = carousel.querySelectorAll('.carousel-indicator');
const interval = options.interval || 10000;
let currentIndex = 0;
let timer = null;
function showSlide(index) {
slides.forEach((slide, i) => {
slide.classList.toggle('active', i === index);
});
indicators.forEach((ind, i) => {
ind.classList.toggle('active', i === index);
ind.setAttribute('aria-selected', i === index);
});
currentIndex = index;
}
function next() {
showSlide((currentIndex + 1) % slides.length);
}
function startAutoplay() {
if (slides.length > 1) {
timer = setInterval(next, interval);
}
}
function stopAutoplay() {
clearInterval(timer);
}
// Pause on hover/focus
carousel.addEventListener('mouseenter', stopAutoplay);
carousel.addEventListener('mouseleave', startAutoplay);
carousel.addEventListener('focusin', stopAutoplay);
carousel.addEventListener('focusout', startAutoplay);
// Indicator clicks
indicators.forEach((ind, i) => {
ind.addEventListener('click', () => showSlide(i));
});
startAutoplay();
}
return { init };
})();
ScrollSpy with IntersectionObserver (~30 lines)
// static/website/js/scrollspy.js
const ScrollSpy = (function() {
'use strict';
function init(tocSelector, contentSelector) {
const toc = document.querySelector(tocSelector);
const headings = document.querySelectorAll(`${contentSelector} h2[id], ${contentSelector} h3[id]`);
if (!toc || !headings.length) return;
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
const link = toc.querySelector(`a[href="#${entry.target.id}"]`);
if (link) {
link.classList.toggle('is-active-link', entry.isIntersecting);
}
});
}, {
rootMargin: '-80px 0px -80% 0px'
});
headings.forEach(heading => observer.observe(heading));
}
return { init };
})();
Phase 3: Replace Grid System (Week 2-3)
New Utility Classes
Add to design-tokens.css:
/* =============================================================================
LAYOUT UTILITIES (Bootstrap Grid Replacement)
============================================================================= */
/* Container */
.container {
width: 100%;
max-width: var(--container-max-width, 1200px);
margin-inline: auto;
padding-inline: var(--space-4);
}
.container-fluid {
width: 100%;
padding-inline: var(--space-4);
}
/* Flexbox Row */
.row {
display: flex;
flex-wrap: wrap;
margin-inline: calc(var(--space-4) * -0.5);
}
.row > * {
padding-inline: calc(var(--space-4) * 0.5);
}
/* Grid-based columns (simpler than Bootstrap's 12-col) */
.grid {
display: grid;
gap: var(--space-4);
}
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
/* Common layout patterns */
.layout-sidebar {
display: grid;
grid-template-columns: 1fr;
gap: var(--space-6);
}
@media (min-width: 992px) {
.layout-sidebar {
grid-template-columns: 250px 1fr;
}
.layout-sidebar-right {
grid-template-columns: 1fr 300px;
}
}
.layout-8-4 {
display: grid;
grid-template-columns: 1fr;
gap: var(--space-4);
}
@media (min-width: 992px) {
.layout-8-4 {
grid-template-columns: 2fr 1fr;
}
}
/* Responsive visibility */
.hide-mobile { display: none; }
.hide-tablet { display: block; }
.hide-desktop { display: block; }
@media (min-width: 576px) {
.hide-mobile { display: block; }
.hide-tablet { display: none; }
}
@media (min-width: 992px) {
.hide-tablet { display: block; }
.hide-desktop { display: none; }
}
/* For cases where you need the 12-column grid */
.grid-12 {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: var(--space-4);
}
.col-span-1 { grid-column: span 1; }
.col-span-2 { grid-column: span 2; }
.col-span-3 { grid-column: span 3; }
.col-span-4 { grid-column: span 4; }
.col-span-6 { grid-column: span 6; }
.col-span-8 { grid-column: span 8; }
.col-span-12 { grid-column: span 12; }
@media (min-width: 992px) {
.md\:col-span-2 { grid-column: span 2; }
.md\:col-span-4 { grid-column: span 4; }
.md\:col-span-8 { grid-column: span 8; }
.md\:col-span-10 { grid-column: span 10; }
}
Template Migration Pattern
<!-- Before (Bootstrap) -->
<div class="container">
<div class="row">
<div class="col-md-8">Main content</div>
<div class="col-md-4 hidden-xs hidden-sm">Sidebar</div>
</div>
</div>
<!-- After (Custom) -->
<div class="container">
<div class="layout-8-4">
<main>Main content</main>
<aside class="hide-mobile hide-tablet">Sidebar</aside>
</div>
</div>
Phase 4: Remove Bootstrap Files (Week 3)
- Delete
static/website/css/bootstrap.css
- Delete
static/website/css/bootstrap-theme.css
- Delete
static/website/css/bootstrap-modifications.css
- Remove Bootstrap CDN script from
base.html
- Remove jQuery CDN script from
base.html
- Run full visual regression test
File-by-File Migration Checklist
Templates to Update
JavaScript to Update/Create
CSS to Update
Effort Estimate
| Task |
Hours |
Priority |
| Vanilla navbar JS |
2 |
High |
| Vanilla carousel JS |
3 |
High |
| Vanilla popover (update existing) |
2 |
Medium |
| Vanilla ScrollSpy |
1 |
Medium |
| Layout utility CSS |
2 |
High |
| Template grid migration (~15 files) |
8-12 |
High |
| Testing & visual QA |
4 |
High |
| Total |
22-26 hours |
|
Benefits Summary
| Benefit |
Impact |
| Bundle size reduction |
-200KB (Bootstrap CSS + JS + jQuery) |
| Security |
Remove jQuery 1.9.1 vulnerabilities |
| Performance |
Faster page loads, no unused CSS |
| Maintainability |
Single styling system (design tokens) |
| Developer experience |
Modern CSS/JS, no framework quirks |
| Future-proofing |
No external dependency updates needed |
Risks & Mitigations
| Risk |
Likelihood |
Mitigation |
| Visual regressions |
Medium |
Screenshot comparison before/after each template |
| Edge cases in old browsers |
Low |
Your audience is academic/tech - modern browsers |
| Timeline slip |
Medium |
Migrate incrementally, keep Bootstrap until each page is done |
| Popover complexity |
Low |
Existing citationPopoverSimple.js handles most logic |
Recommendation
Proceed with migration. The codebase is already 70% transitioned to custom CSS. The remaining work is straightforward, and the long-term benefits (security, performance, maintainability) justify the ~25 hour investment.
Suggested Timeline
- Week 1: Remove jQuery, create vanilla JS components
- Week 2: Migrate high-traffic pages (index, publications, people)
- Week 3: Migrate remaining pages, remove Bootstrap, final QA
Appendix: Quick Reference
Bootstrap → Custom Class Mapping
| Bootstrap Class |
Custom Replacement |
container |
container (keep, redefine) |
row |
row or grid or specific layout |
col-md-8 |
md:col-span-8 or layout class |
col-md-4 |
md:col-span-4 or layout class |
hidden-xs |
hide-mobile |
hidden-sm |
hide-tablet |
hidden-md hidden-lg |
hide-desktop |
visible-xs |
(use default + hide others) |
pull-right |
margin-left: auto or flexbox |
text-center |
text-center (keep) |
New Layout Patterns
<!-- Two-column with sidebar -->
<div class="layout-sidebar">...</div>
<!-- 8-4 split -->
<div class="layout-8-4">...</div>
<!-- Equal columns -->
<div class="grid-3">...</div>
<!-- Custom 12-col when needed -->
<div class="grid-12">
<div class="col-span-8 md:col-span-10">...</div>
<div class="col-span-4 md:col-span-2">...</div>
</div>
I asked Claude about whether or not we should now completely drop our Bootstrap 3.3.6 dependency given our recent
design-tokens.cssrefactor. Response: https://claude.ai/share/6ae8d3a1-461e-45ff-84e7-cbdd2efe2dd5Bootstrap Migration Analysis: Makeability Lab Website
Date: January 2, 2026
Current Stack: Bootstrap 3.3.6 + jQuery 1.9.1
Recommendation: Drop Bootstrap, go fully custom with vanilla CSS/JS
Executive Summary
The Makeability Lab website has evolved to the point where Bootstrap is more burden than benefit. With
design-tokens.cssand modern CSS (flexbox/grid) already powering the newer components, you're essentially maintaining two styling systems. Removing Bootstrap eliminates ~200KB of overridden CSS/JS, removes jQuery security concerns, and simplifies the codebase.Current Bootstrap Usage Analysis
Component Inventory
hidden-xs, etc.)Grid Class Distribution
JavaScript Dependencies
Why NOT Upgrade to Bootstrap 5
col-xs-*→col-*)Verdict: Migration effort is similar, but dropping Bootstrap yields better long-term outcomes.
Migration Strategy
Phase 1: Remove jQuery (Week 1)
Risk: Low | Impact: High
jQuery 1.9.1 (2013) has known security vulnerabilities. Replace with vanilla JS.
Files to update:
website/templates/website/base.html(remove jQuery script tag)website/static/website/js/top-navbar.jswebsite/static/website/js/citationPopoverSimple.jsPhase 2: Replace Bootstrap JS Components (Week 1-2)
Navbar Toggle (~20 lines)
Carousel (~60 lines)
ScrollSpy with IntersectionObserver (~30 lines)
Phase 3: Replace Grid System (Week 2-3)
New Utility Classes
Add to
design-tokens.css:Template Migration Pattern
Phase 4: Remove Bootstrap Files (Week 3)
static/website/css/bootstrap.cssstatic/website/css/bootstrap-theme.cssstatic/website/css/bootstrap-modifications.cssbase.htmlbase.htmlFile-by-File Migration Checklist
Templates to Update
website/templates/website/base.html- Remove Bootstrap/jQuery, add new JSwebsite/templates/website/index.html- Carousel markupwebsite/templates/website/project.html- Carousel, gridwebsite/templates/website/member.html- Grid layoutwebsite/templates/website/publications.html- Grid, ScrollSpywebsite/templates/website/people.html- Grid (already mostly custom)website/templates/website/project_listing.html- Grid (already mostly custom)website/templates/website/news_item.html- Grid layoutwebsite/templates/website/news_listing.html- Grid (already custom)website/templates/snippets/display_pub_snippet.html- Column classeswebsite/templates/snippets/display_citation_link_snippet.html- PopoverJavaScript to Update/Create
static/website/js/navbar.jsstatic/website/js/carousel.jsstatic/website/js/scrollspy.jsstatic/website/js/citationPopoverSimple.js- Remove jQuerystatic/website/js/top-navbar.js- Remove jQueryCSS to Update
design-tokens.csswith layout utilitiestop-navbar.cssfor vanilla collapsepublications.cssfor vanilla ScrollSpy statesbootstrap.css,bootstrap-theme.css,bootstrap-modifications.cssEffort Estimate
Benefits Summary
Risks & Mitigations
citationPopoverSimple.jshandles most logicRecommendation
Proceed with migration. The codebase is already 70% transitioned to custom CSS. The remaining work is straightforward, and the long-term benefits (security, performance, maintainability) justify the ~25 hour investment.
Suggested Timeline
Appendix: Quick Reference
Bootstrap → Custom Class Mapping
containercontainer(keep, redefine)rowroworgridor specific layoutcol-md-8md:col-span-8or layout classcol-md-4md:col-span-4or layout classhidden-xshide-mobilehidden-smhide-tablethidden-md hidden-lghide-desktopvisible-xspull-rightmargin-left: autoor flexboxtext-centertext-center(keep)New Layout Patterns