Creating Interactive Maps with CSS

It is possible to create some nice interactive maps without using any JavaScript if that is something you want to do, but whatever your goals are there are probably better ways to accomplish them.

I will be making an Electoral College map, but other maps are possible if you know what to change. I created an SVG map of the United States from this project and want to let users click on states to change the color and update some statistics.

Label Clip-Path

I want each state to be clickable so I will add a group of labels for each state. Each possible color for each state needs its own label that refers back to a unique radio button. To get these labels to fill the shapes of geographic regions, I set the clip-path url to a clipPath element defined in the svg.

The units for the clip path are pixels so 1 pixel needs to equal 1 SVG unit. We could use objectBoundingBox but then the units are fractions of the width and height so the SVG paths would need to be adjusted. Instead I will create labels with size in pixels matching the viewBox and then use transform to scale the element to match the SVG.

{% for name, item in regions %}
<div id="label-{{name}}" style="clip-path: url(#clip-{{name}});">
<label class="color1 color1-{{name}}" for="color1-{{name}}" ></label>
<label class="color2 color2-{{name}}" for="color2-{{name}}" ></label>
<label class="color3 color3-{{name}}" for="color3-{{name}}" ></label>
</div>
{% endfor %}

I want to also create SVG paths for each state to generate the borders (and text labels, but that could be part of the label). To avoid sending duplicate path data, you can use the <use> element.

Once you have clipped the labels, the logic of changing the color of a state is simple. We will just rotate through the labels. When color 1 is selected we will display the label for color 2, but we want that button to have the first color. We repeat until the final color has the label for color 1 again.

#labels > div > label:Not(.color1) {
display: none;
}
.color1 {
background: var(--color3);
}
.color2 {
background: var(--color1);
}
.color3 {
background: var(--color2);
}
{% for name, item in regions %}
.color1-{{name}}:checked ~ #labels label.color2-{{name}} {
display: block;
}
.color2-{{name}}:checked ~ #labels label.color3-{{name}} {
display: block;
}
{% endfor %}

At this point we have a simple working map with some randomly pre-checked inputs for variety. This repl has the code to generate something similar. Click the states below to rotate between blue, grey, and red.

Info Box

To help users decide which color is appropriate for each state, I want to display an information box in the bottom left. There will be a boxes with historical election results for each state that will be hidden by default. When a user hovers over or clicks on a state that box will become visible. To make the clicks work we use :focus. After a click the focus will be on an input for that state until another input is clicked.

{% for name, item in regions %}
input[name=radio-{{name}}]:focus ~ #info #info-{{name}} {
display: block;
z-index: 1;
}
#label-{{name}}:hover ~ #info #info-{{name}} {
display: block;
z-index: 2;
}
{% endfor %}

In order to make the :focus work the inputs cannot be set to display:none. We will give them opacity 0 and prevent any pointer events. A downside is that clicking a state will scroll the input onto the screen. If the map is full screen that is not really a problem, but for something like this post it is a minor annoyance.

At this stage we have election result information so we will use that to pre-check states based on their voting preferences in 2020. And the label for each state will show the number of electoral votes that state will have in 2024.

MINNESOTA
YearDR%
200414450141346695D+3
200815733541275409D+10
201215461671320225D+7
201613677051322949D+1
202017170771484065D+7
MONTANA
YearDR%
2004173710266063R+21
2008231667242763R+2
2012201839267928R+14
2016177709279240R+22
2020244786343602R+16
NORTH DAKOTA
YearDR%
2004111052196651R+27
2008141278168601R+8
2012124966188320R+20
201693758216794R+39
2020114902235595R+34
HAWAII
YearDR%
2004231708194191D+8
2008325871120566D+45
2012306658121015D+43
2016266891128847D+34
2020366130196864D+30
IDAHO
YearDR%
2004181098409235R+38
2008236440403012R+26
2012212787420911R+32
2016189765409055R+36
2020287021554119R+31
WASHINGTON
YearDR%
200415102011304894D+7
200817508481229216D+17
201217553961290670D+15
201617427181221747D+17
202023696121584651D+19
ARIZONA
YearDR%
20048935241104294R+10
200810347071230111R+8
201210252321233654R+9
201611611671252401R+3
202016721431661686D+0
CALIFORNIA
YearDR%
200467454855509826D+10
200882744735011781D+24
201278542854839958D+23
201687537884483810D+32
2020111102506006429D+29
YearDR%
200410017321101255R+4
200812885761073589D+9
201213231011185243D+5
201613388701202484D+5
202018043521364607D+13
YearDR%
2004397190418690R+2
2008533736412827D+12
2012531373463567D+6
2016539260512058D+2
2020703486669890D+2
NEW MEXICO
YearDR%
2004370942376930R+0
2008472422346832D+15
2012415335335788D+10
2016385234319667D+9
2020501614401894D+11
OREGON
YearDR%
2004943163866831D+4
20081037291738475D+16
2012970488754175D+12
20161002106782403D+12
20201340383958448D+16
UTAH
YearDR%
2004241199663742R+46
2008327670596030R+29
2012251813740600R+49
2016310674515211R+24
2020560282865140R+21
WYOMING
YearDR%
200470776167629R+40
200882868164958R+33
201269286170962R+42
201655973174419R+51
202073491193559R+44
ARKANSAS
YearDR%
2004469953572898R+9
2008422310638017R+20
2012394409647744R+24
2016380494684872R+28
2020423932760647R+28
IOWA
YearDR%
2004741898751957R+0
2008828940682379D+9
2012822544730617D+5
2016653669800983R+10
2020759061897672R+8
KANSAS
YearDR%
2004434993736456R+25
2008514765699655R+15
2012440726692634R+22
2016427005671018R+22
2020570323771406R+14
MISSOURI
YearDR%
200412591711455713R+7
200814419111445814R+0
201212237961482440R+9
201610710681594511R+19
202012530141718736R+15
YearDR%
2004254328512814R+33
2008333319452979R+15
2012302081475064R+22
2016284494495961R+27
2020374583556846R+19
OKLAHOMA
YearDR%
2004503966959792R+31
2008502496960165R+31
2012443547891325R+33
2016420375949136R+38
20205038901020280R+33
SOUTH DAKOTA
YearDR%
2004149244232584R+21
2008170924203054R+8
2012145039210610R+18
2016117458227721R+31
2020150471261043R+26
LOUISIANA
YearDR%
20048202991102169R+14
20087829891148275R+18
20128091411152262R+17
20167801541178638R+20
20208560341255776R+18
TEXAS
YearDR%
200428327044526917R+23
200835286334479328R+11
201233081244569843R+16
201638778684685047R+9
202052591265890347R+5
CONNECTICUT
YearDR%
2004857488693826D+10
2008997772629428D+22
2012905083634892D+17
2016897572673215D+14
20201080831714717D+20
MASSACHUSETTS
YearDR%
200418038001071109D+25
200819040971108854D+26
201219212901188314D+23
201619951961090893D+29
202023822021167202D+34
NEW HAMPSHIRE
YearDR%
2004340511331237D+1
2008384826316534D+9
2012369561329918D+5
2016348526345790D+0
2020424921365654D+7
RHODE ISLAND
YearDR%
2004259760169046D+21
2008296571165391D+28
2012279677157204D+28
2016252525180543D+16
2020307486199922D+21
VERMONT
YearDR%
2004184067121180D+20
200821926298974D+37
201219923992698D+36
201617857395369D+30
2020242820112704D+36
ALABAMA
YearDR%
20046939331176394R+25
20088134791266546R+21
20127956961255925R+22
20167295471318255R+28
20208496241441170R+25
FLORIDA
YearDR%
200435835443964522R+5
200842820744045624D+2
201242377564163447D+0
201645049754617886R+1
202052970455668731R+3
GEORGIA
YearDR%
200413661491914254R+16
200818441232048759R+5
201217738272078688R+7
201618779632089104R+5
202024736332461854D+0
MISSISSIPPI
YearDR%
2004457766672660R+19
2008554662724597R+13
2012562949710746R+11
2016485131700714R+18
2020539398756764R+16
SOUTH CAROLINA
YearDR%
2004661669937974R+17
20088624491034896R+9
20128659411071645R+10
20168553731155389R+14
202010915411385103R+11
ILLINOIS
YearDR%
200428915502345946D+10
200834193482031179D+25
201230195122135216D+17
201630907292146015D+18
202034719152446891D+17
INDIANA
YearDR%
20049690111479438R+20
200813740391345648D+1
201211528871420543R+10
201610331261557286R+20
202012424161729519R+16
KENTUCKY
YearDR%
20047127331069439R+20
20087519851048462R+16
20126793701087190R+23
20166288541202971R+31
20207724741326646R+26
NORTH CAROLINA
YearDR%
200415258491961166R+12
200821426512128474D+0
201221783912270395R+2
201621893162362631R+3
202026842922758773R+1
OHIO
YearDR%
200427411652859764R+2
200829400442677820D+4
201228276212661407D+3
201623941642841005R+8
202026791653154834R+8
TENNESSEE
YearDR%
200410364771384375R+14
200810874371479178R+15
20129607091462330R+20
20168706951522925R+27
202011437111852475R+23
VIRGINIA
YearDR%
200414547421716959R+8
200819595321725005D+6
201219718201822522D+3
201619814731769443D+5
202024135681962430D+10
WISCONSIN
YearDR%
200414895041478120D+0
200816772111262393D+14
201216209851410966D+6
201613825361405284R+0
202016308661610184D+0
WEST VIRGINIA
YearDR%
2004326541423778R+12
2008303857397466R+13
2012238269417655R+27
2016188794489371R+44
2020235984545382R+39
DELAWARE
YearDR%
2004200152171660D+7
2008255459152374D+25
2012242584165484D+18
2016235603185127D+11
2020296268200603D+19
DISTRICT OF COLUMBIA
YearDR%
200420297021256D+81
200824580017367D+86
201226707021381D+85
201628283012723D+91
202031732318586D+88
MARYLAND
YearDR%
200471024703R+99
20081629467959862D+25
20121677844971869D+26
201678259R+53
20201985023976414D+34
NEW JERSEY
YearDR%
200419114301670003D+6
200822154221613207D+15
201221227861478088D+17
201621482781601933D+14
202026083351883274D+16
NEW YORK
YearDR%
200441807552806993D+19
200846453322418323D+31
201243242282223397D+32
201643797892527142D+26
202052309853244798D+23
PENNSYLVANIA
YearDR%
200429380952793847D+2
200832763632655885D+10
201229902742680434D+5
201629264412970733R+0
202034582293377674D+1
MAINE
YearDR%
2004396842330201D+9
2008421923295273D+17
2012401306292276D+15
2016357735335593D+3
2020435072360737D+9
MICHIGAN
YearDR%
200424791832313746D+3
200828725792048639D+16
201225645692115256D+9
201622688392279543R+0
202028040402649852D+2
YearDR%
2004111025190889R+26
2008123594193841R+22
2012122640164676R+14
2016116454163387R+16
2020153778189951R+10

Computing Sums

I'm going to use two different techniques to display the totals for each category. At the top will be a bar that visually showcases the status of the race. In the bottom right the exact numbers of electoral votes of each color will be displayed.

For the bar at the top we will create a flex element. Then we will add 538 elements inside. Each state will control exactly as many of these elements as it has electoral votes. When the color of a state changes we will change the color of these elements as well. Crucially we will also change the order property of these elements so that all elements of the same color remain together to make the visualization useful.

{% for name, item in regions %}
{% for c in colors %}
.color{{loop.index}}-{{name}}:checked ~ .map-container #info .visual-{{name}} {
background: var(--color{{loop.index}});
order: {{loop.index}};
}
{% endfor %}
{% endfor %}

To display the correct number we will create elements with each possible number (0-538) and then make sure that the correct number is shifted into a visible area. To shift the correct amount, we create elements for each state with widths corresponding to their number of electoral votes. If the state is a different color then we hide these elements so that the total width of the visible elements corresponds to the sum.

The CSS will only display the span of the selected color.
{% for name, item in regions %}
	{% for c in colors %}
	.color{{loop.index}}-{{name}}:checked ~ .map-container #info #blocker-{{loop.index}}-{{name}} {
	display: inline-block;
	}
	{% endfor %}
{% endfor %}


The HTML will look like this for the first color output.

<div>
Color 1:
<span class="scoreHolder">
<span class="scoreInner">
{% for name, item in regions %}
<span id="blocker-1-{{name}}" class="blocker" style="width: calc(48px * {{ item['ev']}});">
</span>
{% endfor %}
{% for i in range(0,538+1) %}
<span class="score">{{538 - i}}</span>
{% endfor %}
</span>
</span>
</div>

Then just position everything so that the correct number is visible. Only the 539th set of 48px chunks in the .scoreInner span will be visible. When all of the .blocker spans are visible this chunk will be the first .score span which displays the number 538. As spans are removed the number visible decreases by the same amount.

.scoreHolder {
	width: 48px;
	overflow: hidden;
}
.scoreInner {
width: calc((538 + 1) * 48px);
	right: 0px;
	overflow: hidden;
}
.score {
width: 48px;
}

Our map is now quite nice to use. The only thing this map is missing is proper handling of Maine and Nebraska, but adding a few more rectangles in the right place will solve that later.

MINNESOTA
YearDR%
200414450141346695D+3
200815733541275409D+10
201215461671320225D+7
201613677051322949D+1
202017170771484065D+7
MONTANA
YearDR%
2004173710266063R+21
2008231667242763R+2
2012201839267928R+14
2016177709279240R+22
2020244786343602R+16
NORTH DAKOTA
YearDR%
2004111052196651R+27
2008141278168601R+8
2012124966188320R+20
201693758216794R+39
2020114902235595R+34
HAWAII
YearDR%
2004231708194191D+8
2008325871120566D+45
2012306658121015D+43
2016266891128847D+34
2020366130196864D+30
IDAHO
YearDR%
2004181098409235R+38
2008236440403012R+26
2012212787420911R+32
2016189765409055R+36
2020287021554119R+31
WASHINGTON
YearDR%
200415102011304894D+7
200817508481229216D+17
201217553961290670D+15
201617427181221747D+17
202023696121584651D+19
ARIZONA
YearDR%
20048935241104294R+10
200810347071230111R+8
201210252321233654R+9
201611611671252401R+3
202016721431661686D+0
CALIFORNIA
YearDR%
200467454855509826D+10
200882744735011781D+24
201278542854839958D+23
201687537884483810D+32
2020111102506006429D+29
YearDR%
200410017321101255R+4
200812885761073589D+9
201213231011185243D+5
201613388701202484D+5
202018043521364607D+13
YearDR%
2004397190418690R+2
2008533736412827D+12
2012531373463567D+6
2016539260512058D+2
2020703486669890D+2
NEW MEXICO
YearDR%
2004370942376930R+0
2008472422346832D+15
2012415335335788D+10
2016385234319667D+9
2020501614401894D+11
OREGON
YearDR%
2004943163866831D+4
20081037291738475D+16
2012970488754175D+12
20161002106782403D+12
20201340383958448D+16
UTAH
YearDR%
2004241199663742R+46
2008327670596030R+29
2012251813740600R+49
2016310674515211R+24
2020560282865140R+21
WYOMING
YearDR%
200470776167629R+40
200882868164958R+33
201269286170962R+42
201655973174419R+51
202073491193559R+44
ARKANSAS
YearDR%
2004469953572898R+9
2008422310638017R+20
2012394409647744R+24
2016380494684872R+28
2020423932760647R+28
IOWA
YearDR%
2004741898751957R+0
2008828940682379D+9
2012822544730617D+5
2016653669800983R+10
2020759061897672R+8
KANSAS
YearDR%
2004434993736456R+25
2008514765699655R+15
2012440726692634R+22
2016427005671018R+22
2020570323771406R+14
MISSOURI
YearDR%
200412591711455713R+7
200814419111445814R+0
201212237961482440R+9
201610710681594511R+19
202012530141718736R+15
YearDR%
2004254328512814R+33
2008333319452979R+15
2012302081475064R+22
2016284494495961R+27
2020374583556846R+19
OKLAHOMA
YearDR%
2004503966959792R+31
2008502496960165R+31
2012443547891325R+33
2016420375949136R+38
20205038901020280R+33
SOUTH DAKOTA
YearDR%
2004149244232584R+21
2008170924203054R+8
2012145039210610R+18
2016117458227721R+31
2020150471261043R+26
LOUISIANA
YearDR%
20048202991102169R+14
20087829891148275R+18
20128091411152262R+17
20167801541178638R+20
20208560341255776R+18
TEXAS
YearDR%
200428327044526917R+23
200835286334479328R+11
201233081244569843R+16
201638778684685047R+9
202052591265890347R+5
CONNECTICUT
YearDR%
2004857488693826D+10
2008997772629428D+22
2012905083634892D+17
2016897572673215D+14
20201080831714717D+20
MASSACHUSETTS
YearDR%
200418038001071109D+25
200819040971108854D+26
201219212901188314D+23
201619951961090893D+29
202023822021167202D+34
NEW HAMPSHIRE
YearDR%
2004340511331237D+1
2008384826316534D+9
2012369561329918D+5
2016348526345790D+0
2020424921365654D+7
RHODE ISLAND
YearDR%
2004259760169046D+21
2008296571165391D+28
2012279677157204D+28
2016252525180543D+16
2020307486199922D+21
VERMONT
YearDR%
2004184067121180D+20
200821926298974D+37
201219923992698D+36
201617857395369D+30
2020242820112704D+36
ALABAMA
YearDR%
20046939331176394R+25
20088134791266546R+21
20127956961255925R+22
20167295471318255R+28
20208496241441170R+25
FLORIDA
YearDR%
200435835443964522R+5
200842820744045624D+2
201242377564163447D+0
201645049754617886R+1
202052970455668731R+3
GEORGIA
YearDR%
200413661491914254R+16
200818441232048759R+5
201217738272078688R+7
201618779632089104R+5
202024736332461854D+0
MISSISSIPPI
YearDR%
2004457766672660R+19
2008554662724597R+13
2012562949710746R+11
2016485131700714R+18
2020539398756764R+16
SOUTH CAROLINA
YearDR%
2004661669937974R+17
20088624491034896R+9
20128659411071645R+10
20168553731155389R+14
202010915411385103R+11
ILLINOIS
YearDR%
200428915502345946D+10
200834193482031179D+25
201230195122135216D+17
201630907292146015D+18
202034719152446891D+17
INDIANA
YearDR%
20049690111479438R+20
200813740391345648D+1
201211528871420543R+10
201610331261557286R+20
202012424161729519R+16
KENTUCKY
YearDR%
20047127331069439R+20
20087519851048462R+16
20126793701087190R+23
20166288541202971R+31
20207724741326646R+26
NORTH CAROLINA
YearDR%
200415258491961166R+12
200821426512128474D+0
201221783912270395R+2
201621893162362631R+3
202026842922758773R+1
OHIO
YearDR%
200427411652859764R+2
200829400442677820D+4
201228276212661407D+3
201623941642841005R+8
202026791653154834R+8
TENNESSEE
YearDR%
200410364771384375R+14
200810874371479178R+15
20129607091462330R+20
20168706951522925R+27
202011437111852475R+23
VIRGINIA
YearDR%
200414547421716959R+8
200819595321725005D+6
201219718201822522D+3
201619814731769443D+5
202024135681962430D+10
WISCONSIN
YearDR%
200414895041478120D+0
200816772111262393D+14
201216209851410966D+6
201613825361405284R+0
202016308661610184D+0
WEST VIRGINIA
YearDR%
2004326541423778R+12
2008303857397466R+13
2012238269417655R+27
2016188794489371R+44
2020235984545382R+39
DELAWARE
YearDR%
2004200152171660D+7
2008255459152374D+25
2012242584165484D+18
2016235603185127D+11
2020296268200603D+19
DISTRICT OF COLUMBIA
YearDR%
200420297021256D+81
200824580017367D+86
201226707021381D+85
201628283012723D+91
202031732318586D+88
MARYLAND
YearDR%
200471024703R+99
20081629467959862D+25
20121677844971869D+26
201678259R+53
20201985023976414D+34
NEW JERSEY
YearDR%
200419114301670003D+6
200822154221613207D+15
201221227861478088D+17
201621482781601933D+14
202026083351883274D+16
NEW YORK
YearDR%
200441807552806993D+19
200846453322418323D+31
201243242282223397D+32
201643797892527142D+26
202052309853244798D+23
PENNSYLVANIA
YearDR%
200429380952793847D+2
200832763632655885D+10
201229902742680434D+5
201629264412970733R+0
202034582293377674D+1
MAINE
YearDR%
2004396842330201D+9
2008421923295273D+17
2012401306292276D+15
2016357735335593D+3
2020435072360737D+9
MICHIGAN
YearDR%
200424791832313746D+3
200828725792048639D+16
201225645692115256D+9
201622688392279543R+0
202028040402649852D+2
YearDR%
2004111025190889R+26
2008123594193841R+22
2012122640164676R+14
2016116454163387R+16
2020153778189951R+10
Likely D:5385375365355345335325315305295285275265255245235225215205195185175165155145135125115105095085075065055045035025015004994984974964954944934924914904894884874864854844834824814804794784774764754744734724714704694684674664654644634624614604594584574564554544534524514504494484474464454444434424414404394384374364354344334324314304294284274264254244234224214204194184174164154144134124114104094084074064054044034024014003993983973963953943933923913903893883873863853843833823813803793783773763753743733723713703693683673663653643633623613603593583573563553543533523513503493483473463453443433423413403393383373363353343333323313303293283273263253243233223213203193183173163153143133123113103093083073063053043033023013002992982972962952942932922912902892882872862852842832822812802792782772762752742732722712702692682672662652642632622612602592582572562552542532522512502492482472462452442432422412402392382372362352342332322312302292282272262252242232222212202192182172162152142132122112102092082072062052042032022012001991981971961951941931921911901891881871861851841831821811801791781771761751741731721711701691681671661651641631621611601591581571561551541531521511501491481471461451441431421411401391381371361351341331321311301291281271261251241231221211201191181171161151141131121111101091081071061051041031021011009998979695949392919089888786858483828180797877767574737271706968676665646362616059585756555453525150494847464544434241403938373635343332313029282726252423222120191817161514131211109876543210
Battle:5385375365355345335325315305295285275265255245235225215205195185175165155145135125115105095085075065055045035025015004994984974964954944934924914904894884874864854844834824814804794784774764754744734724714704694684674664654644634624614604594584574564554544534524514504494484474464454444434424414404394384374364354344334324314304294284274264254244234224214204194184174164154144134124114104094084074064054044034024014003993983973963953943933923913903893883873863853843833823813803793783773763753743733723713703693683673663653643633623613603593583573563553543533523513503493483473463453443433423413403393383373363353343333323313303293283273263253243233223213203193183173163153143133123113103093083073063053043033023013002992982972962952942932922912902892882872862852842832822812802792782772762752742732722712702692682672662652642632622612602592582572562552542532522512502492482472462452442432422412402392382372362352342332322312302292282272262252242232222212202192182172162152142132122112102092082072062052042032022012001991981971961951941931921911901891881871861851841831821811801791781771761751741731721711701691681671661651641631621611601591581571561551541531521511501491481471461451441431421411401391381371361351341331321311301291281271261251241231221211201191181171161151141131121111101091081071061051041031021011009998979695949392919089888786858483828180797877767574737271706968676665646362616059585756555453525150494847464544434241403938373635343332313029282726252423222120191817161514131211109876543210
Likely R:5385375365355345335325315305295285275265255245235225215205195185175165155145135125115105095085075065055045035025015004994984974964954944934924914904894884874864854844834824814804794784774764754744734724714704694684674664654644634624614604594584574564554544534524514504494484474464454444434424414404394384374364354344334324314304294284274264254244234224214204194184174164154144134124114104094084074064054044034024014003993983973963953943933923913903893883873863853843833823813803793783773763753743733723713703693683673663653643633623613603593583573563553543533523513503493483473463453443433423413403393383373363353343333323313303293283273263253243233223213203193183173163153143133123113103093083073063053043033023013002992982972962952942932922912902892882872862852842832822812802792782772762752742732722712702692682672662652642632622612602592582572562552542532522512502492482472462452442432422412402392382372362352342332322312302292282272262252242232222212202192182172162152142132122112102092082072062052042032022012001991981971961951941931921911901891881871861851841831821811801791781771761751741731721711701691681671661651641631621611601591581571561551541531521511501491481471461451441431421411401391381371361351341331321311301291281271261251241231221211201191181171161151141131121111101091081071061051041031021011009998979695949392919089888786858483828180797877767574737271706968676665646362616059585756555453525150494847464544434241403938373635343332313029282726252423222120191817161514131211109876543210

Final Product

For the code to generate everything, see this repl. The /createCSS url gives you a few options to change the set of colors or the default values and then the form is posted to generate the map.

There is also a JavaScript version that adds the ability to change colors by dragging left or right.