Table of Contents
Start at baseline
Rendering data points
Rendering line segments
Applying transformation, it's great
When to use such charts
Potential improvements
Responsive
Axis
Margins
Home Web Front-end CSS Tutorial How to Make a Line Chart With CSS

How to Make a Line Chart With CSS

Apr 09, 2025 am 11:36 AM

How to Make a Line Chart With CSS

The cornerstones of the dashboard are line charts, bar charts, and pie charts, which are essential components of any data visualization toolkit. Of course, you can use JavaScript chart libraries like SVG or Chart.js, or a complex tool like D3 to create these charts, but what if you don't want to load another library into a website that you already have performance-constrained?

There are a lot of articles on how to create bar charts, bar charts and pie charts that use CSS only, but if you only need a basic line chart, you are in bad luck. While CSS can "draw lines" using borders, etc., there is no clear way to draw from one point to another on the X and Y coordinate planes.

There is indeed a way! If you only need a simple line chart, you don't need to load large JavaScript libraries, or even use SVG. You can create everything you need with just some custom properties in CSS and HTML. However, it is important to remind you that this does involve some trigonometry. If that doesn't scare you, then let's get started!

Here are our goals:

Start at baseline

If you are creating a line chart by hand (like actually drawing lines on chart paper), you will first create points and then connect these points to form the lines. If you break down the process like this, you can recreate any basic line chart in CSS.

Suppose we have an array of data to display points on X and Y coordinate systems, where the day of the week is on the X axis and the numerical value represents the points on the Y axis.

 <code>[ { value: 25, dimension: "Monday" }, { value: 60, dimension: "Tuesday" }, { value: 45, dimension: "Wednesday" }, { value: 50, dimension: "Thursday" }, { value: 40, dimension: "Friday" } ]</code>
Copy after login

Let's create an unordered list to save our data points and apply some styles to them. Here is our HTML:

Copy after login
Copy after login
<li>
<li>
<li>
<li>
<li>

A few points to pay attention to here. First, we wrap everything in one<ul></ul> Among elements, this is a good way to semantic HTML, indicating that this is self-contained content, and can also be used if needed.<figcaption></figcaption> The added benefits. Second, please note that we store the value in a custom property called data-value , which is included in itself<div> In, the<code><div> Located in the list item in the unordered list. Why we use separate<code><div> Instead of putting the class and attributes in the list item itself? This will help us later when drawing lines.<p> Finally, note that we have an inline custom property on the parent element, which we call <code>--widget-size . We will use it in CSS, which will look like this:

 <code>/* 父元素*/ .css-chart { /* 图表边框*/ border-bottom: 1px solid; border-left: 1px solid; /* 高度,最初在HTML中定义*/ height: var(--widget-size); /* 如果图表周围有其他项目,则留出一些空间*/ margin: 1em; /* 删除任何填充,以便我们在元素内部有尽可能多的空间可以使用*/ padding: 0; position: relative; /* 图表宽度,在HTML中定义*/ width: var(--widget-size); } /* 包含数据点的无序列表,没有列表样式和间距*/ .line-chart { list-style: none; margin: 0; padding: 0; } /* 图表上的每个点,每个都是一个带浅色边框的12px圆圈*/ .data-point { background-color: white; border: 2px solid lightblue; border-radius: 50%; height: 12px; position: absolute; width: 12px; }</code>
Copy after login

The HTML and CSS above will give us this less exciting starting point:

Rendering data points

This doesn't look like a chart yet. We need a way to plot each data point on the respective X and Y coordinates on the chart to be generated. In our CSS we set .data-point class to use absolute positioning and set fixed width and height on its parent .css-chart container using custom properties. We can use it to calculate our X and Y positions.

Our custom properties set the chart height to 200px and in our value array the maximum is 60. If we set this data point to the highest point (200px) on the Y axis of the chart, then we can use the ratio of any value in the dataset to 60 and multiply it by 200 to get the Y coordinates of all points. Therefore, our maximum value of 60 will have a Y value that can be calculated like this:

 <code>(60 / 60) * 200 = 200px</code>
Copy after login

And our smallest value of 25 will calculate the Y value in the same way:

 <code>(25 / 60) * 200 = 83.33333333333334px</code>
Copy after login

It is easier to get the Y coordinates of each data point. If we spread the points evenly on the chart, we can divide the width of the chart (200px) by the number of values ​​in the data array (5) to get 40px. This means that the X coordinate of the first value will be 40px (you can leave margins for the left axis if we want), and the X coordinate of the last value will be 200px.

You just did the math operation! ?

Now, let's go to each of the list items<div> Add inline style. Our new HTML will become like this, where the inline style contains the calculated position of each point.<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false"> </pre><div class="contentsignin">Copy after login</div></div><div class="contentsignin">Copy after login</div></div> <li> <div data-value="25" style="bottom: 83.33333333333334px; left: 40px;"></div> </li> <li> <div data-value="60" style="bottom: 200px; left: 80px;"></div> </li> <li> <div data-value="45" style="bottom: 150px; left: 120px;"></div> </li> <li> <div data-value="50" style="bottom: 166.66666666666669pxpx; left: 160px;"></div> </li> <li> <div data-value="40" style="bottom: 133.33333333333331px; left: 200px;"></div> </li> <p>Hey, this looks much better! But even if you can see what this is going on, you still can't really call it a line chart. no problem. We just need to use <em>a little</em> more math to complete our continuous point game. Check out the picture of the data points we rendered again. Can you see the triangles connecting them? If not, maybe the next image will help:</p> <p> Why is this important? Shhh, the answer is coming soon.</p> <h3 id="Rendering-line-segments"> Rendering line segments</h3> <p> Have you seen the triangle now? They are more than just ordinary triangles. They are our best triangles (for our purposes) because they are <strong>right angle triangles</strong> ! When we calculate the Y coordinates of the data point earlier, we are also calculating the length of one side of a right triangle ("Run" if you think of it as a ladder). If we calculate the difference in the X coordinate from one point to another, this will tell us the length of the other side of the right triangle (i.e. the "rise" of the step). With these two pieces of information, we can calculate the length of the magical bevel, which turns out is exactly what we need to draw onto the screen to connect our points and make a real line chart.</p> <p> For example, let's look at the second and third points on the chart.</p> <p> The Y value of the second data point is 200 and the Y value of the third data point is 150, so the opposite side length of the triangle connecting them is 200 minus 150, i.e. 50. It has a 40-pixel-long neighbor (the spacing we leave between each point).</p> <p> This means that the length of the hypotenuse is 50 squares plus 40 squares of squares, i.e. 64.03124237432849.</p> <p> Let's create another one within each list item in the chart<code><div> , it will act as the hypotenuse of the triangle drawn from that point. Then, we will be in this new<code><div> Set an inline custom property on which contains the length of the bevel.<p> At the same time, our line segments need to know their correct X and Y coordinates, so let's remove the inline style from <code>.data-point element, but in its parent element (<li> Add CSS custom attributes to element). Let's creatively refer to these properties --x and --y . Our data points do not need to know the bevel (the length of the segment), so we can add CSS custom properties for the bevel length directly to .line-segment . So now our HTML will look like this:

We need to update the CSS to locate the data points with these new custom properties and set up the new .line-segment we add to the tag<div> Style:<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false"> &lt;code&gt;.data-point { /* 和以前一样*/ bottom: var(--y); left: var(--x); } .line-segment { background-color: blue; bottom: var(--y); height: 3px; left: var(--x); position: absolute; width: calc(var(--hypotenuse) * 1px); }&lt;/code&gt;</pre><div class="contentsignin">Copy after login</div></div> <p> OK, we have segments now, but that's not what we want at all. To get a line chart with normal function, we need to apply the conversion. But first, let's fix some issues.</p> <p> First, our segment aligns with the bottom of the data point, but we want the origin of the segment to be in the center of the data point circle. We can solve this problem by quickly changing <code>.data-point style CSS. We need to adjust their X and Y positions to take into account both the size of the data points and their borders and the width of the line segments.

 <code>.data-point { /* ... */ /* 数据点的半径为8px,线段的宽度为3px,  因此我们将差值分成两半,以使数据点位于线段原点的中心*/ bottom: calc(var(--y) - 6.5px); left: calc(var(--x) - 9.5px); }</code>
Copy after login

Second, our line segments are rendered at the top of the data point rather than behind it. We can solve this problem by putting the line segment first in HTML:

Applying transformation, it's great

We're almost done. We only need to do the last bit of math. Specifically, we need to find a measure of the angle opposite to the opposite side of a right triangle and then rotate our segments by the same degree.

How do we do it? Trigonometry! You may also remember little memory tips for how to calculate sine, cosine, and tangent:

    <li> SOH (sine = opposite side/oblique side) <li> CAH (cosine = adjacent/oblique) <li> TOA (tangent = opposite side/near side)

You can use either because we know the length of all three sides of a right triangle. I chose the sine, so this leaves us with this equation:

 <code>sin(x) = 对边/ 斜边</code>
Copy after login

The answer to this equation will tell us how to rotate each line segment to connect it to the next data point. We can do this quickly using Math.asin(Opposite / Hypotenuse) in JavaScript. But it gives the answer in radians, so we need to multiply the result by (180 / Math.PI) .

Using our second data point example above, we have calculated that the paired edge length is 50 and the beveled edge length is 64.03124237432849, so we can rewrite our equation as:

 <code>sin(x) = 50 / 64.03124237432849 = 51.34019174590991</code>
Copy after login

This is the angle we are looking for! We need to solve the equation for each data point and then pass that value to our .line-segment element as a CSS custom property. This will make our HTML look like this:

And here we can apply these properties in CSS:

 <code>.line-segment { /* ... */ transform: rotate(calc(var(--angle) * 1deg)); width: calc(var(--hypotenuse) * 1px); }</code>
Copy after login

Now, when we render it, we finally get the line chart we've been waiting for using CSS only.

Important Note: When you calculate the value of the opposite edge ("rise"), make sure to calculate it as "Y position of the current data point" minus "Y position of the next data point". When the value of the next data point is greater than the current data point (higher on the chart), this will result in a negative value, which will result in a negative rotation. This is how we make sure the lines are tilted upwards.

When to use such charts

This approach is perfect for simple static websites or dynamic websites that use server-side generated content. Of course, it can also be used on sites with dynamically generated content on the client side, but then you go back to running JavaScript on the client side. The CodePen at the top of this article shows an example of how the client generates this line chart dynamically.

The CSS calc() function is very useful, but it cannot calculate sine, cosine, and tangent for us. This means you have to calculate your values ​​manually, or write a quick function (client or server side) to generate the required values ​​(X, Y, bevel and angle) for our CSS custom properties.

I know some of you went through this process and if you needed a script to calculate the value, it felt like it wasn't pure CSS - that's fair. The key is that all the graph rendering is done in CSS. The points and lines connecting them are all done using HTML elements and CSS, and they work perfectly even in static rendering environments without JavaScript enabled. Perhaps more importantly, you can render a simple line chart on your page without downloading another bloated library.

Potential improvements

Like anything, we can always do something to take things to the next level. In this case, I think this approach can be improved through three aspects.

Responsive

The method I outlined uses a fixed size for chart sizes, which is exactly what we don't want to see in responsive design. If we can run JavaScript on the client, we can resolve this limitation. Instead of hardcoded the chart size, set a CSS custom property (remember our --widget-size property?), do all the calculations based on it, and update that property using some kind of container query or window resize listener when the container or window is initially displayed or resized.

Tooltips

We can add a ::before pseudo-element to .data-point to display the data-value information it contains when hovering over a data point. This is a nice addition and helps turn our simple chart into a finished product.

Axis

Please note that the chart axes are not marked? We can distribute labels on the axes representing the highest value, zero, and any number of points between them.

Margins

I'm trying to make the numbers in this article as simple as possible, but in the real world you might want to include some margins in the chart so that the data points don't overlap with the extreme edges of the container. This may be simple, just subtract the width of the data point from the range of the y-coordinate. For X coordinates, you can also subtract the width of the data point from the total width of the chart similarly before dividing the chart into equal areas.

That's it! We just looked at a way to chart in CSS, and we don't even need libraries or other third-party dependencies to make it work. ?

The above is the detailed content of How to Make a Line Chart With CSS. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Vue 3 Vue 3 Apr 02, 2025 pm 06:32 PM

It&#039;s out! Congrats to the Vue team for getting it done, I know it was a massive effort and a long time coming. All new docs, as well.

Building an Ethereum app using Redwood.js and Fauna Building an Ethereum app using Redwood.js and Fauna Mar 28, 2025 am 09:18 AM

With the recent climb of Bitcoin’s price over 20k $USD, and to it recently breaking 30k, I thought it’s worth taking a deep dive back into creating Ethereum

Can you get valid CSS property values from the browser? Can you get valid CSS property values from the browser? Apr 02, 2025 pm 06:17 PM

I had someone write in with this very legit question. Lea just blogged about how you can get valid CSS properties themselves from the browser. That&#039;s like this.

Stacked Cards with Sticky Positioning and a Dash of Sass Stacked Cards with Sticky Positioning and a Dash of Sass Apr 03, 2025 am 10:30 AM

The other day, I spotted this particularly lovely bit from Corey Ginnivan’s website where a collection of cards stack on top of one another as you scroll.

A bit on ci/cd A bit on ci/cd Apr 02, 2025 pm 06:21 PM

I&#039;d say "website" fits better than "mobile app" but I like this framing from Max Lynch:

Comparing Browsers for Responsive Design Comparing Browsers for Responsive Design Apr 02, 2025 pm 06:25 PM

There are a number of these desktop apps where the goal is showing your site at different dimensions all at the same time. So you can, for example, be writing

Using Markdown and Localization in the WordPress Block Editor Using Markdown and Localization in the WordPress Block Editor Apr 02, 2025 am 04:27 AM

If we need to show documentation to the user directly in the WordPress editor, what is the best way to do it?

Why are the purple slashed areas in the Flex layout mistakenly considered 'overflow space'? Why are the purple slashed areas in the Flex layout mistakenly considered 'overflow space'? Apr 05, 2025 pm 05:51 PM

Questions about purple slash areas in Flex layouts When using Flex layouts, you may encounter some confusing phenomena, such as in the developer tools (d...

See all articles