[{"data":1,"prerenderedAt":1106},["ShallowReactive",2],{"content:\u002Fimage-media-optimization\u002Fsvg-and-icon-optimization\u002Fmigrating-from-icon-fonts-to-svg":3,"surroundings:\u002Fimage-media-optimization\u002Fsvg-and-icon-optimization\u002Fmigrating-from-icon-fonts-to-svg":1097},{"id":4,"title":5,"body":6,"description":1076,"extension":1077,"meta":1078,"navigation":1090,"path":1091,"seo":1092,"stem":1095,"__hash__":1096},"content\u002Fimage-media-optimization\u002Fsvg-and-icon-optimization\u002Fmigrating-from-icon-fonts-to-svg\u002Findex.md","Migrating from Icon Fonts to SVG",{"type":7,"value":8,"toc":1059},"minimark",[9,14,29,41,154,159,203,207,213,219,225,231,293,297,302,315,387,391,394,398,683,687,690,823,827,830,834,844,848,866,870,904,908,922,928,938,944,948,960,973,990,999,1008,1017,1021,1044,1049,1052,1055],[10,11,13],"h1",{"id":12},"how-to-migrate-from-icon-fonts-to-svg-icons","How to Migrate from Icon Fonts to SVG Icons",[15,16,17,18,23,24,28],"p",{},"This guide covers the most common legacy pattern in ",[19,20,22],"a",{"href":21},"\u002Fimage-media-optimization\u002Fsvg-and-icon-optimization\u002F","SVG & Icon Optimization",", part of ",[19,25,27],{"href":26},"\u002Fimage-media-optimization\u002F","Image & Media Optimization",". Icon fonts — Font Awesome's webfont build, Material Icons font, custom IcoMoon sets — were the standard way to ship icons a decade ago. They package hundreds of glyphs into one font file and a stylesheet that maps class names to private-use characters. They also bring the full cost of web fonts to every icon on the page.",[15,30,31,32,36,37,40],{},"The font file and its stylesheet are usually on the critical path. Until the font loads, icons are invisible (with ",[33,34,35],"code",{},"font-display: block",") or render as fallback characters and boxes (with ",[33,38,39],{},"swap","), then pop in — sometimes changing width and shifting layout. Screen readers may announce private-use characters as gibberish. And the font contains every glyph in the set, even if a page uses six. SVG icons solve all of these, and the migration can be done incrementally.",[15,42,43],{},[44,45,51,52,51,59,51,63,51,66,51,75,51,81,51,90,51,96,51,101,51,106,51,109,51,112,51,115,51,118,51,121,51,124,51,129,51,133,51,135,51,139,51,141,51,144,51,146,51,149,51,151,51],"svg",{"viewBox":46,"width":47,"role":48,"ariaLabel":49,"style":50},"0 0 760 228","100%","img","Comparison of the costs of an icon font and an SVG icon system.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[53,54],"rect",{"className":55,"x":57,"y":57,"width":47,"height":47,"fill":58},[56],"svg-canvas","0","#ffffff",[60,61,62],"title",{},"Icon font vs SVG icons",[64,65,49],"desc",{},[53,67],{"x":68,"y":68,"width":69,"height":70,"rx":71,"fill":72,"stroke":73,"style":74},"1","758","226","10","none","currentColor","stroke-opacity:0.18",[76,77,62],"text",{"x":78,"y":79,"fill":73,"style":80},"28.0","34.0","font-size:16px;font-weight:700",[53,82],{"x":78,"y":83,"width":84,"height":85,"rx":86,"fill":87,"stroke":88,"style":89},"56.0","340.0","150.0","6","#ffc300","#b8860b","fill-opacity:0.24;stroke-opacity:0.9",[76,91,95],{"x":92,"y":93,"fill":73,"style":94},"42.0","82.0","font-size:14px;font-weight:700","Icon font",[76,97,100],{"x":92,"y":98,"fill":73,"style":99},"108.0","font-size:12.5px;font-weight:700","•",[76,102,105],{"x":83,"y":98,"fill":73,"style":103,"textAnchor":104},"font-size:12.5px","start","CSS + font file on the critical path",[76,107,100],{"x":92,"y":108,"fill":73,"style":99},"132.0",[76,110,111],{"x":83,"y":108,"fill":73,"style":103,"textAnchor":104},"Icons invisible or wrong until font loads",[76,113,100],{"x":92,"y":114,"fill":73,"style":99},"156.0",[76,116,117],{"x":83,"y":114,"fill":73,"style":103,"textAnchor":104},"Swap can shift layout",[76,119,100],{"x":92,"y":120,"fill":73,"style":99},"180.0",[76,122,123],{"x":83,"y":120,"fill":73,"style":103,"textAnchor":104},"All glyphs shipped; a11y pitfalls",[53,125],{"x":126,"y":83,"width":84,"height":85,"rx":86,"fill":127,"stroke":127,"style":128},"392.0","#0466c8","fill-opacity:0.14;stroke-opacity:0.9",[76,130,132],{"x":131,"y":93,"fill":73,"style":94},"406.0","SVG icons",[76,134,100],{"x":131,"y":98,"fill":73,"style":99},[76,136,138],{"x":137,"y":98,"fill":73,"style":103,"textAnchor":104},"420.0","Inline or sprite: no font request",[76,140,100],{"x":131,"y":108,"fill":73,"style":99},[76,142,143],{"x":137,"y":108,"fill":73,"style":103,"textAnchor":104},"Icons render with the HTML",[76,145,100],{"x":131,"y":114,"fill":73,"style":99},[76,147,148],{"x":137,"y":114,"fill":73,"style":103,"textAnchor":104},"Fixed dimensions: no shift",[76,150,100],{"x":131,"y":120,"fill":73,"style":99},[76,152,153],{"x":137,"y":120,"fill":73,"style":103,"textAnchor":104},"Only icons used; aria-hidden or labelled",[155,156,158],"h2",{"id":157},"rapid-diagnosis","Rapid Diagnosis",[160,161,162,181,191,197],"ul",{},[163,164,165,169,170,173,174,173,177,180],"li",{},[166,167,168],"strong",{},"Find icon fonts in the Network panel."," Filter by Font; look for files named like ",[33,171,172],{},"fa-solid-900.woff2",", ",[33,175,176],{},"icomoon",[33,178,179],{},"MaterialIcons",".",[163,182,183,186,187,190],{},[166,184,185],{},"Check the CSS cost."," Icon font stylesheets often contain hundreds of ",[33,188,189],{},".icon-x:before { content: \"\\f123\" }"," rules; check their size in Coverage.",[163,192,193,196],{},[166,194,195],{},"Watch the first paint."," On a throttled load, are icons missing or showing as boxes before popping in?",[163,198,199,202],{},[166,200,201],{},"Check accessibility."," Run axe: icon elements without accessible names or with announced private-use characters.",[155,204,206],{"id":205},"root-cause-analysis","Root Cause Analysis",[15,208,209,212],{},[166,210,211],{},"1. Font loading on the critical path."," Icons cannot render until the font arrives, and the font is discovered only after its stylesheet loads.",[15,214,215,218],{},[166,216,217],{},"2. Swap behaviour."," With fallback rendering, glyph widths differ, and buttons or text containing icons reflow when the real font arrives.",[15,220,221,224],{},[166,222,223],{},"3. Unused glyphs."," Hundreds of icons ship for the handful a page uses.",[15,226,227,230],{},[166,228,229],{},"4. Semantics."," Icons in pseudo-elements carry no accessible name, and private-use code points can be read aloud.",[15,232,233],{},[44,234,51,237,51,240,51,243,51,245,51,248,51,250,51,257,51,264,51,269,51,273,51,277,51,281,51,284,51,289,51],{"viewBox":235,"width":47,"role":48,"ariaLabel":236,"style":50},"0 0 760 163","Bar chart comparing bytes on the critical path for header icons delivered via an icon font and via SVG.",[53,238],{"className":239,"x":57,"y":57,"width":47,"height":47,"fill":58},[56],[60,241,242],{},"Critical-path cost of icons on a header + navigation",[64,244,236],{},[53,246],{"x":68,"y":68,"width":69,"height":247,"rx":71,"fill":72,"stroke":73,"style":74},"161",[76,249,242],{"x":78,"y":79,"fill":73,"style":80},[76,251,256],{"x":252,"y":253,"fill":73,"style":254,"textAnchor":255},"151.9","70.0","font-size:13px","end","Icon font WOFF2",[53,258],{"x":259,"y":83,"width":260,"height":261,"rx":262,"fill":87,"stroke":88,"style":263},"163.9","504.1","19","3","fill-opacity:0.7;stroke-opacity:0.9",[76,265,268],{"x":266,"y":253,"fill":73,"style":267},"674.0","font-size:12px;font-weight:600","78KB",[76,270,272],{"x":252,"y":271,"fill":73,"style":254,"textAnchor":255},"101.0","Icon font CSS",[53,274],{"x":259,"y":275,"width":276,"height":261,"rx":262,"fill":87,"stroke":88,"style":263},"87.0","200.4",[76,278,280],{"x":279,"y":271,"fill":73,"style":267},"370.2","31KB",[76,282,283],{"x":252,"y":108,"fill":73,"style":254,"textAnchor":255},"SVG sprite (12 icons)",[53,285],{"x":259,"y":286,"width":287,"height":261,"rx":262,"fill":127,"stroke":127,"style":288},"118.0","22.0","fill-opacity:0.55;stroke-opacity:0.9",[76,290,292],{"x":291,"y":108,"fill":73,"style":267},"191.8","3.4KB",[155,294,296],{"id":295},"step-by-step-migration","Step-by-Step Migration",[298,299,301],"h3",{"id":300},"_1-inventory-the-icons-actually-used","1. Inventory the icons actually used",[15,303,304,305,173,308,173,311,314],{},"Grep templates for icon class names (",[33,306,307],{},"fa-",[33,309,310],{},"icon-",[33,312,313],{},"material-icons"," text content) and list the distinct icons per area of the site. Most sites use a small fraction of the font's glyphs.",[316,317,322],"pre",{"className":318,"code":319,"language":320,"meta":321,"style":321},"language-bash shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","grep -rhoE 'fa-[a-z0-9-]+' src\u002F | sort | uniq -c | sort -rn | head -50\n# trade-off: dynamically built class names (e.g. `fa-${name}`) will not appear\n# in a grep; search for the patterns that build them too.\n","bash","",[33,323,324,374,381],{"__ignoreMap":321},[325,326,329,333,337,341,344,348,351,353,356,359,361,363,366,368,371],"span",{"class":327,"line":328},"line",1,[325,330,332],{"class":331},"sQw3B","grep",[325,334,336],{"class":335},"sPXB4"," -rhoE",[325,338,340],{"class":339},"sZ8jY"," 'fa-[a-z0-9-]+'",[325,342,343],{"class":339}," src\u002F",[325,345,347],{"class":346},"sPARh"," |",[325,349,350],{"class":331}," sort",[325,352,347],{"class":346},[325,354,355],{"class":331}," uniq",[325,357,358],{"class":335}," -c",[325,360,347],{"class":346},[325,362,350],{"class":331},[325,364,365],{"class":335}," -rn",[325,367,347],{"class":346},[325,369,370],{"class":331}," head",[325,372,373],{"class":335}," -50\n",[325,375,377],{"class":327,"line":376},2,[325,378,380],{"class":379},"sjfSM","# trade-off: dynamically built class names (e.g. `fa-${name}`) will not appear\n",[325,382,384],{"class":327,"line":383},3,[325,385,386],{"class":379},"# in a grep; search for the patterns that build them too.\n",[298,388,390],{"id":389},"_2-build-an-svg-icon-set-for-those-icons","2. Build an SVG icon set for those icons",[15,392,393],{},"Most icon libraries publish SVG sources (Font Awesome, Material Symbols, Lucide, Heroicons). Export the used icons, optimise with SVGO, and build a sprite or per-icon components.",[298,395,397],{"id":396},"_3-introduce-an-icon-component-that-supports-both-systems","3. Introduce an icon component that supports both systems",[316,399,403],{"className":400,"code":401,"language":402,"meta":321,"style":321},"language-jsx shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F\u002F Icon.jsx — renders SVG when available, falls back to the font during migration.\nconst SVG_ICONS = new Set(['search', 'cart', 'user', 'menu', 'close', 'star']);\nexport function Icon({ name, label, size = 20 }) {\n  if (SVG_ICONS.has(name)) {\n    return React.createElement('svg', { width: size, height: size, role: label ? 'img' : undefined,\n      'aria-label': label, 'aria-hidden': label ? undefined : true },\n      React.createElement('use', { href: `\u002Ficons\u002Fsprite.7c1d.svg#${name}` }));\n  }\n  return \u003Ci className={`fa fa-${name}`} aria-hidden={!label} aria-label={label} \u002F>;\n}\n\u002F\u002F trade-off: running both systems temporarily keeps the font on the page;\n\u002F\u002F the win arrives only when the last font icon on a template is gone.\n","jsx",[33,404,405,410,463,498,518,554,581,608,614,665,671,677],{"__ignoreMap":321},[325,406,407],{"class":327,"line":328},[325,408,409],{"class":379},"\u002F\u002F Icon.jsx — renders SVG when available, falls back to the font during migration.\n",[325,411,412,415,418,421,424,428,432,435,437,440,442,445,447,450,452,455,457,460],{"class":327,"line":376},[325,413,414],{"class":346},"const",[325,416,417],{"class":335}," SVG_ICONS",[325,419,420],{"class":346}," =",[325,422,423],{"class":346}," new",[325,425,427],{"class":426},"smZ65"," Set",[325,429,431],{"class":430},"saISM","([",[325,433,434],{"class":339},"'search'",[325,436,173],{"class":430},[325,438,439],{"class":339},"'cart'",[325,441,173],{"class":430},[325,443,444],{"class":339},"'user'",[325,446,173],{"class":430},[325,448,449],{"class":339},"'menu'",[325,451,173],{"class":430},[325,453,454],{"class":339},"'close'",[325,456,173],{"class":430},[325,458,459],{"class":339},"'star'",[325,461,462],{"class":430},"]);\n",[325,464,465,468,471,474,477,480,482,485,487,490,492,495],{"class":327,"line":383},[325,466,467],{"class":346},"export",[325,469,470],{"class":346}," function",[325,472,473],{"class":426}," Icon",[325,475,476],{"class":430},"({ ",[325,478,479],{"class":331},"name",[325,481,173],{"class":430},[325,483,484],{"class":331},"label",[325,486,173],{"class":430},[325,488,489],{"class":331},"size",[325,491,420],{"class":346},[325,493,494],{"class":335}," 20",[325,496,497],{"class":430}," }) {\n",[325,499,501,504,507,510,512,515],{"class":327,"line":500},4,[325,502,503],{"class":346},"  if",[325,505,506],{"class":430}," (",[325,508,509],{"class":335},"SVG_ICONS",[325,511,180],{"class":430},[325,513,514],{"class":426},"has",[325,516,517],{"class":430},"(name)) {\n",[325,519,521,524,527,530,533,536,539,542,545,548,551],{"class":327,"line":520},5,[325,522,523],{"class":346},"    return",[325,525,526],{"class":430}," React.",[325,528,529],{"class":426},"createElement",[325,531,532],{"class":430},"(",[325,534,535],{"class":339},"'svg'",[325,537,538],{"class":430},", { width: size, height: size, role: label ",[325,540,541],{"class":346},"?",[325,543,544],{"class":339}," 'img'",[325,546,547],{"class":346}," :",[325,549,550],{"class":335}," undefined",[325,552,553],{"class":430},",\n",[325,555,557,560,563,566,569,571,573,575,578],{"class":327,"line":556},6,[325,558,559],{"class":339},"      'aria-label'",[325,561,562],{"class":430},": label, ",[325,564,565],{"class":339},"'aria-hidden'",[325,567,568],{"class":430},": label ",[325,570,541],{"class":346},[325,572,550],{"class":335},[325,574,547],{"class":346},[325,576,577],{"class":335}," true",[325,579,580],{"class":430}," },\n",[325,582,584,587,589,591,594,597,600,602,605],{"class":327,"line":583},7,[325,585,586],{"class":430},"      React.",[325,588,529],{"class":426},[325,590,532],{"class":430},[325,592,593],{"class":339},"'use'",[325,595,596],{"class":430},", { href: ",[325,598,599],{"class":339},"`\u002Ficons\u002Fsprite.7c1d.svg#${",[325,601,479],{"class":430},[325,603,604],{"class":339},"}`",[325,606,607],{"class":430}," }));\n",[325,609,611],{"class":327,"line":610},8,[325,612,613],{"class":430},"  }\n",[325,615,617,620,623,627,630,633,636,638,640,643,646,649,651,653,656,658,660,662],{"class":327,"line":616},9,[325,618,619],{"class":346},"  return",[325,621,622],{"class":430}," \u003C",[325,624,626],{"class":625},"sZBmE","i",[325,628,629],{"class":335}," className",[325,631,632],{"class":346},"={",[325,634,635],{"class":339},"`fa fa-${",[325,637,479],{"class":430},[325,639,604],{"class":339},[325,641,642],{"class":346},"}",[325,644,645],{"class":335}," aria-hidden",[325,647,648],{"class":346},"={!",[325,650,484],{"class":430},[325,652,642],{"class":346},[325,654,655],{"class":335}," aria-label",[325,657,632],{"class":346},[325,659,484],{"class":430},[325,661,642],{"class":346},[325,663,664],{"class":430}," \u002F>;\n",[325,666,668],{"class":327,"line":667},10,[325,669,670],{"class":430},"}\n",[325,672,674],{"class":327,"line":673},11,[325,675,676],{"class":379},"\u002F\u002F trade-off: running both systems temporarily keeps the font on the page;\n",[325,678,680],{"class":327,"line":679},12,[325,681,682],{"class":379},"\u002F\u002F the win arrives only when the last font icon on a template is gone.\n",[298,684,686],{"id":685},"_4-migrate-template-by-template-then-remove-the-font","4. Migrate template by template, then remove the font",[15,688,689],{},"Convert high-traffic templates first; when a template uses no font icons, stop loading the icon font CSS on it. When no template does, delete the font and stylesheet and add a CI check that fails if they return.",[15,691,692],{},[44,693,51,696,51,699,51,702,51,704,51,707,51,709,51,714,51,720,51,725,51,728,51,732,51,736,51,739,51,743,51,747,51,750,51,754,51,758,51,761,51,765,51,769,51,776,51,780,51,784,51,788,51,793,51,796,51,799,51,803,51,806,51,809,51,812,51,816,51,819,51],{"viewBox":694,"width":47,"role":48,"ariaLabel":695,"style":50},"0 0 760 381","Five steps to migrate from an icon font to SVG icons without a big-bang rewrite.",[53,697],{"className":698,"x":57,"y":57,"width":47,"height":47,"fill":58},[56],[60,700,701],{},"Incremental icon font migration",[64,703,695],{},[53,705],{"x":68,"y":68,"width":69,"height":706,"rx":71,"fill":72,"stroke":73,"style":74},"379",[76,708,701],{"x":78,"y":79,"fill":73,"style":80},[53,710],{"x":711,"y":83,"width":712,"height":713,"rx":86,"fill":127,"stroke":127,"style":128},"72.0","660.0","51.0",[76,715,719],{"x":716,"y":717,"fill":73,"style":718,"textAnchor":104},"86.0","77.0","font-size:13px;font-weight:700","Inventory used icons",[76,721,724],{"x":716,"y":722,"fill":73,"style":723,"textAnchor":104},"94.0","font-size:12px","Usually a few dozen of hundreds",[53,726],{"x":711,"y":727,"width":712,"height":713,"rx":86,"fill":127,"stroke":127,"style":128},"119.0",[76,729,731],{"x":716,"y":730,"fill":73,"style":718,"textAnchor":104},"140.0","Build an optimised SVG set",[76,733,735],{"x":716,"y":734,"fill":73,"style":723,"textAnchor":104},"157.0","Sprite or components from the library's SVG sources",[53,737],{"x":711,"y":738,"width":712,"height":713,"rx":86,"fill":127,"stroke":127,"style":128},"182.0",[76,740,742],{"x":716,"y":741,"fill":73,"style":718,"textAnchor":104},"203.0","Dual-mode Icon component",[76,744,746],{"x":716,"y":745,"fill":73,"style":723,"textAnchor":104},"220.0","SVG where available, font as fallback",[53,748],{"x":711,"y":749,"width":712,"height":713,"rx":86,"fill":127,"stroke":127,"style":128},"245.0",[76,751,753],{"x":716,"y":752,"fill":73,"style":718,"textAnchor":104},"266.0","Migrate top templates first",[76,755,757],{"x":716,"y":756,"fill":73,"style":723,"textAnchor":104},"283.0","Drop the font CSS per template when unused",[53,759],{"x":711,"y":760,"width":712,"height":713,"rx":86,"fill":127,"stroke":127,"style":128},"308.0",[76,762,764],{"x":716,"y":763,"fill":73,"style":718,"textAnchor":104},"329.0","Remove the font everywhere",[76,766,768],{"x":716,"y":767,"fill":73,"style":723,"textAnchor":104},"346.0","CI check prevents its return",[327,770],{"x1":771,"y1":772,"x2":771,"y2":773,"stroke":73,"strokeWidth":774,"style":775},"43.0","95.5","130.5","1.5","stroke-opacity:0.3",[327,777],{"x1":771,"y1":778,"x2":771,"y2":779,"stroke":73,"strokeWidth":774,"style":775},"158.5","193.5",[327,781],{"x1":771,"y1":782,"x2":771,"y2":783,"stroke":73,"strokeWidth":774,"style":775},"221.5","256.5",[327,785],{"x1":771,"y1":786,"x2":771,"y2":787,"stroke":73,"strokeWidth":774,"style":775},"284.5","319.5",[789,790],"circle",{"cx":771,"cy":791,"r":792,"fill":127},"81.5","13",[76,794,68],{"x":771,"y":716,"fill":58,"style":718,"textAnchor":795},"middle",[789,797],{"cx":771,"cy":798,"r":792,"fill":127},"144.5",[76,800,802],{"x":771,"y":801,"fill":58,"style":718,"textAnchor":795},"149.0","2",[789,804],{"cx":771,"cy":805,"r":792,"fill":127},"207.5",[76,807,262],{"x":771,"y":808,"fill":58,"style":718,"textAnchor":795},"212.0",[789,810],{"cx":771,"cy":811,"r":792,"fill":127},"270.5",[76,813,815],{"x":771,"y":814,"fill":58,"style":718,"textAnchor":795},"275.0","4",[789,817],{"cx":771,"cy":818,"r":792,"fill":127},"333.5",[76,820,822],{"x":771,"y":821,"fill":58,"style":718,"textAnchor":795},"338.0","5",[155,824,826],{"id":825},"verification","Verification",[15,828,829],{},"On migrated templates, the Network panel should show no icon font or icon CSS requests. Icons should render in the first paint at their final size, with no layout shift (check Layout Shift Regions). Accessibility checks should show decorative icons hidden and meaningful icons labelled. Compare LCP and CLS on migrated templates; removing a render-blocking icon stylesheet often improves LCP by 100–300ms on mobile.",[155,831,833],{"id":832},"worked-example-a-banking-portal","Worked Example: A Banking Portal",[15,835,836,837,839,840,843],{},"A banking portal loaded a 120KB custom icon font plus a 36KB stylesheet on every page, with ",[33,838,35],{},"; on slow connections, navigation icons and buttons with icon-only labels were invisible for up to three seconds, and screen reader users heard private-use characters. The inventory found 58 icons in use. The team shipped an SVG sprite (6KB), an ",[33,841,842],{},"Icon"," component with proper labels, and migrated over three sprints. Removing the font eliminated 156KB from the critical path, LCP p75 improved by 260ms, CLS from button reflows dropped from 0.06 to near zero, and accessibility audits passed for the first time.",[155,845,847],{"id":846},"accessibility-gains-from-the-migration","Accessibility Gains From the Migration",[15,849,850,851,854,855,858,859,862,863,865],{},"The migration is also an accessibility fix, and worth planning as one. Decide for each icon whether it is decorative (",[33,852,853],{},"aria-hidden=\"true\"",", no label) or meaningful (an accessible name via ",[33,856,857],{},"aria-label"," on the control, or ",[33,860,861],{},"role=\"img\""," with a label on the SVG). Icon-only buttons need a label on the button. SVG also respects forced-colours modes (Windows High Contrast) when drawn with ",[33,864,73],{},", which icon fonts often fail. Run an accessibility audit before and after; the improvement is usually as visible as the performance one.",[155,867,869],{"id":868},"common-mistakes","Common Mistakes",[160,871,872,878,884,898],{},[163,873,874,877],{},[166,875,876],{},"Converting all icons at once."," Large, risky change; migrate incrementally.",[163,879,880,883],{},[166,881,882],{},"Inlining every icon."," Repeated icons should use a sprite to avoid DOM bloat.",[163,885,886,889,890,893,894,897],{},[166,887,888],{},"Losing icon sizing."," Font icons sized by ",[33,891,892],{},"font-size","; SVG icons need explicit width\u002Fheight or ",[33,895,896],{},"1em"," sizing to match.",[163,899,900,903],{},[166,901,902],{},"Forgetting dynamic icon names."," Icons chosen at runtime must be in the sprite.",[155,905,907],{"id":906},"edge-cases","Edge Cases",[15,909,910,913,914,917,918,921],{},[166,911,912],{},"Icons in CSS pseudo-elements."," Replace ",[33,915,916],{},":before"," icons with inline elements or CSS ",[33,919,920],{},"mask-image"," using the SVG file.",[15,923,924,927],{},[166,925,926],{},"Third-party widgets using the same font."," Some embedded tools rely on your icon font; check before removing it globally.",[15,929,930,933,934,937],{},[166,931,932],{},"Ligature-based fonts (Material Icons)."," Text like ",[33,935,936],{},"shopping_cart"," renders as an icon only after the font loads; without the font it shows the word — a long, layout-shifting string. Migrating these is especially valuable.",[15,939,940,943],{},[166,941,942],{},"Email templates."," Email clients have limited SVG support; keep raster icons there.",[155,945,947],{"id":946},"faq","FAQ",[949,950,953,957],"details",{"className":951},[952],"faq-item",[954,955,956],"summary",{},"Can I subset the icon font instead of migrating?",[15,958,959],{},"Subsetting reduces bytes, and is a reasonable stopgap, but the font still loads late, risks invisible or shifting icons, and keeps the accessibility problems. Migration solves all of them.",[949,961,963,966],{"className":962},[952],[954,964,965],{},"Is a sprite or inline SVG better for migrated icons?",[15,967,968,969,180],{},"A sprite for most icons, inline for a few that need part-level styling or animation. See ",[19,970,972],{"href":971},"\u002Fimage-media-optimization\u002Fsvg-and-icon-optimization\u002Finline-svg-vs-sprite-vs-img\u002F","inline SVG vs sprite vs img",[949,974,976,979],{"className":975},[952],[954,977,978],{},"How do I size SVG icons like font icons?",[15,980,981,982,985,986,989],{},"Set ",[33,983,984],{},"width: 1em; height: 1em"," on the SVG so it scales with the surrounding font size, and ",[33,987,988],{},"vertical-align: -0.125em"," (or similar) to align with text baselines.",[949,991,993,996],{"className":992},[952],[954,994,995],{},"Will SVG icons look different from the font?",[15,997,998],{},"Slightly, in anti-aliasing and hinting, since fonts get text rendering treatment. Most libraries' SVG versions are drawn to look the same; compare at common sizes.",[949,1000,1002,1005],{"className":1001},[952],[954,1003,1004],{},"Does Font Awesome support SVG directly?",[15,1006,1007],{},"Yes — it provides SVG sprites, per-icon SVG files and framework components; avoid its JavaScript-based SVG replacement on large pages, which scans and rewrites the DOM at runtime.",[949,1009,1011,1014],{"className":1010},[952],[954,1012,1013],{},"How do I prevent the font from coming back?",[15,1015,1016],{},"Add a CI check that fails if the icon font's CSS or font file appears in the build output or is requested on key templates in a headless test.",[155,1018,1020],{"id":1019},"related","Related",[160,1022,1023,1030,1037],{},[163,1024,1025,1029],{},[19,1026,1028],{"href":1027},"\u002Fimage-media-optimization\u002Fsvg-and-icon-optimization\u002Foptimizing-svg-files-with-svgo\u002F","Optimizing SVG files with SVGO"," — preparing the new icons.",[163,1031,1032,1036],{},[19,1033,1035],{"href":1034},"\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Fsubsetting-web-fonts-with-unicode-range\u002F","Subsetting web fonts with unicode-range"," — the interim subsetting option.",[163,1038,1039,1043],{},[19,1040,1042],{"href":1041},"\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Ffixing-cls-from-web-font-swap\u002F","Fixing CLS from web font swap"," — the shift icon fonts cause.",[1045,1046,1048],"script",{"type":1047},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"How to Migrate from Icon Fonts to SVG Icons\",\n  \"description\": \"Why icon fonts hurt LCP, CLS and accessibility, and a step-by-step migration to an SVG icon system without a big-bang rewrite.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Inventory the icons actually used\",\n      \"text\": \"Grep templates for icon class names (fa-, icon-, material-icons text content) and list the distinct icons per area of the site.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Build an SVG icon set for those icons\",\n      \"text\": \"Most icon libraries publish SVG sources (Font Awesome, Material Symbols, Lucide, Heroicons).\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Introduce an icon component that supports both systems\",\n      \"text\": \"Introduce an icon component that supports both systems\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Migrate template by template, then remove the font\",\n      \"text\": \"Convert high-traffic templates first; when a template uses no font icons, stop loading the icon font CSS on it.\"\n    }\n  ]\n}\n",[1045,1050,1051],{"type":1047},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"How to Migrate from Icon Fonts to SVG Icons\",\n  \"description\": \"Why icon fonts hurt LCP, CLS and accessibility, and a step-by-step migration to an SVG icon system without a big-bang rewrite.\",\n  \"datePublished\": \"2026-10-06\",\n  \"dateModified\": \"2026-10-06\",\n  \"author\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"publisher\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"mainEntityOfPage\": {\n    \"@type\": \"WebPage\",\n    \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002Fsvg-and-icon-optimization\u002Fmigrating-from-icon-fonts-to-svg\u002F\"\n  }\n}\n",[1045,1053,1054],{"type":1047},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 1,\n      \"name\": \"Home\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 2,\n      \"name\": \"Image & Media Optimization\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 3,\n      \"name\": \"SVG & Icon Optimization\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002Fsvg-and-icon-optimization\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"Migrating from Icon Fonts to SVG\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002Fsvg-and-icon-optimization\u002Fmigrating-from-icon-fonts-to-svg\u002F\"\n    }\n  ]\n}\n",[1056,1057,1058],"style",{},"html pre.shiki code .sQw3B, html code.shiki .sQw3B{--shiki-default:#702C00;--shiki-dark:#FFB757;--shiki-light:#702C00}html pre.shiki code .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}html pre.shiki code .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}html pre.shiki code .sPARh, html code.shiki .sPARh{--shiki-default:#A0111F;--shiki-dark:#FF9492;--shiki-light:#A0111F}html pre.shiki code .sjfSM, html code.shiki .sjfSM{--shiki-default:#66707B;--shiki-dark:#BDC4CC;--shiki-light:#66707B}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}html pre.shiki code .saISM, html code.shiki .saISM{--shiki-default:#0E1116;--shiki-dark:#F0F3F6;--shiki-light:#0E1116}html pre.shiki code .sZBmE, html code.shiki .sZBmE{--shiki-default:#024C1A;--shiki-dark:#72F088;--shiki-light:#024C1A}",{"title":321,"searchDepth":376,"depth":376,"links":1060},[1061,1062,1063,1069,1070,1071,1072,1073,1074,1075],{"id":157,"depth":376,"text":158},{"id":205,"depth":376,"text":206},{"id":295,"depth":376,"text":296,"children":1064},[1065,1066,1067,1068],{"id":300,"depth":383,"text":301},{"id":389,"depth":383,"text":390},{"id":396,"depth":383,"text":397},{"id":685,"depth":383,"text":686},{"id":825,"depth":376,"text":826},{"id":832,"depth":376,"text":833},{"id":846,"depth":376,"text":847},{"id":868,"depth":376,"text":869},{"id":906,"depth":376,"text":907},{"id":946,"depth":376,"text":947},{"id":1019,"depth":376,"text":1020},"Why icon fonts hurt LCP, CLS and accessibility, and a step-by-step migration to an SVG icon system without a big-bang rewrite.","md",{"slug":1079,"type":1080,"breadcrumb":1081,"datePublished":1089,"dateModified":1089},"migrating-from-icon-fonts-to-svg","article",[1082,1085,1086,1087],{"name":1083,"url":1084},"Home","\u002F",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":1088},"\u002Fimage-media-optimization\u002Fsvg-and-icon-optimization\u002Fmigrating-from-icon-fonts-to-svg\u002F","2026-10-06",true,"\u002Fimage-media-optimization\u002Fsvg-and-icon-optimization\u002Fmigrating-from-icon-fonts-to-svg",{"title":1093,"description":1094},"Migrating from Icon Fonts to SVG Icons","Icon fonts add render-blocking CSS, late font loads, invisible or shifting icons and accessibility issues. Migrate to SVG icons incrementally and safely.","image-media-optimization\u002Fsvg-and-icon-optimization\u002Fmigrating-from-icon-fonts-to-svg\u002Findex","LDhZ8xQRx1ShFQAT-Z82-aQPlRH5wAe6ogzblm9baXY",[1098,1102],{"title":1099,"path":1100,"stem":1101,"children":-1},"Inline SVG vs Sprite vs img","\u002Fimage-media-optimization\u002Fsvg-and-icon-optimization\u002Finline-svg-vs-sprite-vs-img","image-media-optimization\u002Fsvg-and-icon-optimization\u002Finline-svg-vs-sprite-vs-img\u002Findex",{"title":1103,"path":1104,"stem":1105,"children":-1},"Optimizing SVG Files with SVGO","\u002Fimage-media-optimization\u002Fsvg-and-icon-optimization\u002Foptimizing-svg-files-with-svgo","image-media-optimization\u002Fsvg-and-icon-optimization\u002Foptimizing-svg-files-with-svgo\u002Findex",1791308077046]