scale-like-image
v1.2.1
Published
Makes any HTML element scale responsively like an image
Maintainers
Readme
ScaleLikeImage
A lightweight JavaScript library that makes any HTML element scale responsively like an image, maintaining aspect ratio and fitting within its container using CSS transforms.
Features
- 🎯 Simple API - Just pass in your elements, it handles the rest
- 📱 Fully Responsive - Automatically adjusts on window resize, orientation change
- 🎨 Padding Aware - Respects container padding just like native images
- ⚡ Performance Optimized - Uses CSS transforms and ResizeObserver
- 🔧 No Dependencies - Pure vanilla JavaScript, ~4KB minified
- 🌐 Universal - Works with any HTML element (divs, charts, infographics, etc.)
Installation
NPM
npm install scale-like-imageCDN
<script src="https://cdn.jsdelivr.net/npm/scale-like-image@latest/dist/scale-like-image.min.js"></script>Direct Download
<!-- Development (with sourcemap) -->
<script src="dist/scale-like-image.js"></script>
<!-- Production (minified, 4.5KB) -->
<script src="dist/scale-like-image.min.js"></script>ESM Import
import scaleLikeImage from 'scale-like-image';Quick Start
// Make an element scale like an image
scaleLikeImage('#my-chart');
// Multiple elements
scaleLikeImage('.infographic');
// With options
scaleLikeImage('#content', {
defaultWidth: 1200,
maxScale: 1
});How It Works
The library wraps your element in a div and applies CSS transforms to scale it proportionally, just like an image with object-fit: contain. Your element is set to a fixed width internally and visually scales to fit the available space.
Before
<div class="chart">
<!-- Your content -->
</div>After (automatically created)
<div class="sli-wrapper" style="width: 100%; overflow: hidden; height: 300px;">
<div class="chart sli-scaled" style="width: 800px; transform-origin: top left; transform: scale(0.5);">
<!-- Your content -->
</div>
</div>API
scaleLikeImage(elements, options)
Parameters
elements- Can be:- CSS selector string:
'.my-class'or'#my-id' - Single Element:
document.getElementById('chart') - NodeList:
document.querySelectorAll('.item') - Array of Elements:
[elem1, elem2]
- CSS selector string:
options- Configuration object (optional)
Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| defaultWidth | number | 800 | Fixed width applied to the element for scaling calculations (px) |
| maxScale | number | 1 | Maximum scale factor (1 = never scale up) |
| minScale | number | 0 | Minimum scale factor (0 = no limit) |
| maintainHeight | boolean | true | Adjust wrapper height after scaling |
| responsive | boolean | true | Auto-update on resize |
| debounceDelay | number | 100 | Resize debounce delay (ms) |
| className | object | See below | Custom class names |
| onScale | function | null | Callback: (element, scaleFactor) => {} |
| offset | number | 0 | Pixel offset for width calculation |
| scaleBelow | number|null | null | Width threshold — element is natural above this width, scales down like an image below it |
Default Class Names
{
wrapper: 'sli-wrapper',
scaled: 'sli-scaled'
}Return Value
Returns a controller object with these methods:
const controller = scaleLikeImage('#my-element');
// Manually trigger rescaling
controller.update();
// Update options
controller.setOptions({ maxScale: 1.5 });
// Get current scale factors
const scales = controller.getScale();
// Returns: [{ element: Element, scale: 0.75 }]
// Remove all modifications
controller.destroy();
// Access managed elements
controller.elements // Array of elements
controller.wrappers // Array of wrapper divsExamples
Basic Usage
<!-- Your fixed-width element -->
<div id="infographic" style="width: 1200px;">
<h1>My Infographic</h1>
<p>Content that needs to scale...</p>
</div>
<script>
// Make it scale like an image
scaleLikeImage('#infographic');
</script>Multiple Elements
// Scale all dashboard widgets
scaleLikeImage('.dashboard-widget', {
defaultWidth: 600,
maxScale: 1.2
});Manual Control
// Disable auto-resize and control manually
const controller = scaleLikeImage('.manual-element', {
responsive: false
});
// Update when needed
document.getElementById('update-btn').addEventListener('click', () => {
controller.update();
});
// Clean up when done
document.getElementById('remove-btn').addEventListener('click', () => {
controller.destroy();
});With Callback
scaleLikeImage('.tracked-element', {
onScale: (element, scaleFactor) => {
console.log(`Element scaled to ${scaleFactor}`);
// Adjust other elements based on scale
if (scaleFactor < 0.5) {
element.classList.add('small-view');
}
}
});No Width Required
// Elements without width get default 800px
scaleLikeImage('.no-width-element', {
defaultWidth: 1000 // Override default
});Advanced Usage
Dynamic Content
const controller = scaleLikeImage('.dynamic-content');
// After content changes
function loadNewContent() {
// ... modify element content ...
controller.update(); // Recalculate scale
}Responsive Breakpoints
const controller = scaleLikeImage('.responsive-element');
// Adjust options based on viewport
function updateOptions() {
if (window.innerWidth < 768) {
controller.setOptions({ maxScale: 0.8 });
} else {
controller.setOptions({ maxScale: 1 });
}
}
window.addEventListener('resize', updateOptions);Integration with Frameworks
// React example
useEffect(() => {
const controller = scaleLikeImage(ref.current, {
defaultWidth: 1200
});
return () => {
controller.destroy();
};
}, []);Browser Support
- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- Opera (latest)
- IE11 (with ResizeObserver polyfill)
- Mobile browsers (iOS Safari, Chrome Mobile)
Common Use Cases
- Infographics - Fixed-width designs that need to be responsive
- Charts & Graphs - Data visualizations with specific dimensions
- Timeline Components - Horizontal timelines that need to fit containers
- Dashboard Widgets - Fixed-size widgets in responsive layouts
- Marketing Materials - Promotional content with precise layouts
- Interactive Demos - UI components that need proportional scaling
Troubleshooting
Element not scaling
- Check that the wrapper's parent has available width
- Verify JavaScript is loading after DOM is ready
Scale calculation seems wrong
- Check for CSS box-sizing on the wrapper's parent
- Use
offsetoption to fine-tune if needed
Performance issues
- Increase
debounceDelayfor resize events - Consider disabling
responsiveand manually callingupdate() - Use CSS will-change: transform on frequently scaled elements
Tips
defaultWidthis always applied - The library sets your element todefaultWidthand scales from there- Overflow - The wrapper has
overflow: hiddenautomatically - Print styles - Consider destroying/recreating for print:
controller.destroy() - Animations - Apply to the wrapper, not the scaled element
- Z-index issues - Adjust on the wrapper as needed
License
MIT License - see LICENSE file for details
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Support
For issues, questions, or suggestions, please open an issue on GitHub.
