Chart.js chart appears stretched after container width animation despite responsive:true
0 reputation · 27 Mar 2026, 02:52 UTC
0 reputation · 27 Mar 2026, 02:52 UTC
When a Chart.js instance is configured with responsive:true and the default maintainAspectRatio:true, the chart should automatically adjust its canvas size to match changes in the parent container while preserving the original aspect ratio.
In a scenario where the container’s width is animated via a CSS transition (for example, expanding from 200 px to 400 px on hover), the rendered chart sometimes looks stretched or distorted after the animation completes, resembling a stale‑cache effect even though Chart.js does not cache rendered frames.
The uncertainty lies in whether this visual distortion is an expected consequence of the aspect‑ratio constraint conflicting with the container’s size change, or if it indicates a need for an explicit chart.update() after the resize to force a fresh layout calculation.
What conditions cause the stretching behavior, and is manual intervention required to obtain the correct rendering after a container size transition?
33775 reputation · 27 Mar 2026, 10:54 UTC
Manual intervention is required to obtain correct rendering after a CSS transition. The stretching behavior occurs because Chart.js does not continuously track intermediate frames of a CSS-driven animation; it updates the canvas based on resize events or ResizeObserver triggers, which may not align perfectly with the completion of a CSS transition.
When responsive: true and maintainAspectRatio: true are enabled, Chart.js sets the internal canvas drawing surface (the width and height attributes) to match the container's dimensions. However, a CSS transition on the container's width changes the CSS layout size without necessarily updating the canvas attribute size in real-time.
The resulting "stretched" look is not a cache issue, but a browser scaling issue: the browser takes the existing bitmap (rendered at the old size) and stretches it to fit the new CSS dimensions of the container. Because the internal resolution of the canvas is now lower than the displayed size, the chart appears distorted or blurry.
To resolve this, you must force Chart.js to recalculate the canvas dimensions once the animation has reached its final state. Assuming Chart.js v3 or v4, follow these steps:
transitionend event on the parent container to ensure the final width is reached before triggering a redraw..resize()` method on the chart instance. This updates the canvas attributes to match the current CSS dimensions and redraws the chart.const container = document.getElementById('chart-container');
const myChart = new Chart(ctx, config);
container.addEventListener('transitionend', (event) => {
// Only resize if the width property was the one animated
if (event.propertyName === 'width') {
myChart.resize();
}
});
position: relative, absolute, or fixed. Without this, the responsive logic may fail to calculate the container size correctly..update() or .resize() inside a requestAnimationFrame loop during the transition, as this can cause significant flickering and performance degradation.Diagnostic Detail: Are you using transform: scale() instead of width for the animation? If so, ResizeObserver will not detect the change, and a manual .resize() call is mandatory regardless of the event used.
Use comments to ask for clarification. Post a solution as an answer.
33,775 reputation · 27 Mar 2026, 12:14 UTC
Chart.js relies on a ResizeObserver to react to changes in the chart’s container. When the container’s width is animated with a CSS transition, the observer is notified only after the animation completes. During the transition the canvas keeps its original width and height attributes, so the maintainAspectRatio:true logic continues to enforce the old ratio, resulting in a stretched image.
chart.resize() or chart.update() on transitionend to force a recalculation.maintainAspectRatio:false if you want the canvas to simply fill the new width.maintainAspectRatio when the container’s height stays constant.These steps work consistently in Chart.js v4.x and earlier releases that use the same ResizeObserver approach.