Is it possible to get a complete CSS file for make4ht which would account for any output? I am saving HTML outputs created by make4ht to a databank; saving an accompanying CSS file separately for each entry seems redundant to me.

1 Answer 1


It is not so easy, for two reasons:

  1. TeX4ht uses a lot of conditional code, so you may get a different CSS code depending on the used packages or command line options
  2. some elements, most particularly fonts, tables, colored boxes, etc., produce CSS code that depends on the used features like colors or rules in the case of tables.

I have one idea that can work if you always use the same command line options. The following Lua script compares two CSS files, and insert extra CSS instructions from the secondary file to the main file, but it keeps the rules for specific id attributes in the second.

-- filename: updatecss.lua
local main_file = arg[1]
local secondary_file = arg[2]

local function help(err)
  print "Usage: texlua updatecss.lua main_file.css secondary_file.css"
  print "Extra CSS instructions from the secondary_file.css will be inserted to the main_file.css"
  print "In secondary_file.css, only rules that contain #character, will be preserved"
  if err then
    print("Error: " .. err)

local used = {}
local css  = {}
local ids  = {}

local function is_id(line)
  return line:match("^[^%{]*%#") 

local function is_comment(line)
  return line:match("^%s*%/%*")

local function is_empty_line(line)
  return line:match("^%s*$")

if not main_file or not secondary_file then

local main, msg = io.open(main_file, "r")
if not main then

local second, msg = io.open(secondary_file, "r")
if not second then

-- loop over the main file, and save CSS rules that are not comments or depending on the id attribute

for line in main:lines() do
  if not is_id(line) and not is_comment(line) then
    if not is_empty_line(line) then
      table.insert(css, line)
    used[line] = true

-- loop over the secondary file and save extra rules not used in the main css, and also rules for the id attribute

for line in second:lines() do
  if is_id(line) then
    table.insert(ids, line)
  elseif not is_comment(line) and not used[line] then
    used[line] = true
    table.insert( css, line )


-- now write unique CSS without ids and comments to the main_file.css
local main = io.open(main_file, "w")
main:write(table.concat(css, "\n"))

-- and save ids to the secondary file
local second = io.open(secondary_file, "w")
-- we need to import the main CSS file
-- you may need to list full URL here
second:write('@import "' .. main_file .. "\"\n")
second:write(table.concat(ids, ";\n"))


Use it in the following way:

texlua updatecss.lua main.css current.css

This will overwrite both CSS files, the main.css will keep the generic rules, and current.css will have extra rules for specific elements from the current TeX project.

They could look like this after script processing:

.cmbx-10{ font-weight: bold;}
.cmti-10{ font-style: italic;}
p + p{margin-top:1em;}
p + div, p + pre {margin-top:1em;}
div + p, pre + p {margin-top:1em;}
a { overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; hyphens: auto; }
@media print {div.crosslinks {visibility:hidden;}}
table.tabular{border-collapse: collapse; border-spacing: 0;}
a img { border-top: 0; border-left: 0; border-right: 0; }
center { margin-top:1em; margin-bottom:1em; }
td center { margin-top:0em; margin-bottom:0em; }
.Canvas { position:relative; }
div.par-math-display, div.math-display{text-align:center;}
.obeylines-h,.obeylines-v {white-space: nowrap; }
div.obeylines-v p { margin-top:0; margin-bottom:0; }
.overline{ text-decoration:overline; }
.overline img{ border-top: 1px solid black; }
td.displaylines {text-align:center; white-space:nowrap;}
.centerline {text-align:center;}
.rightline {text-align:right;}
.underline{ text-decoration:underline; }
.underline img{ border-bottom: 1px solid black; margin-bottom:1pt; }
div.proclaim { margin-top: 1em; margin-bottom: 1em; }
p.item {text-indent:-2em; margin-left:2em;}
p.itemitem {text-indent:-2em; margin-left:4em;}
span.item, span.itemitem {width:2em; margin-right:0.4em;}
td.eqalign3 { text-align:right; margin-left:10em;}
.eqalign td { white-space: nowrap; }
div.eqalign {text-align:center;}
td.eqalignno3, td.leqalignno3 { text-align:right; margin-left:10em;}
.leqalignno td, .eqalignno td { white-space: nowrap; }
.leqalignno td.noalign, .eqalignno td.noalign { width:5%; white-space: normal; }
table.leqalignno, table.eqalignno {width:100%;}
div.pmatrix {text-align:center;}
table.pmatrix {width:100%;}
.cmtt-10{font-family: monospace,monospace;}
li p.indent { text-indent: 0em }
li p:first-child{ margin-top:0em; }
li p:last-child, li div:last-child { margin-bottom:0.5em; }
li p:first-child{ margin-bottom:0; }
li p~ul:last-child, li p~ol:last-child{ margin-bottom:0.5em; }
.enumerate1 {list-style-type:decimal;}
.enumerate2 {list-style-type:lower-alpha;}
.enumerate3 {list-style-type:lower-roman;}
.enumerate4 {list-style-type:upper-alpha;}
div.newtheorem { margin-bottom: 2em; margin-top: 2em;}
div.newtheorem .head{font-weight: bold;}
pre.verbatim {font-family: monospace,monospace; text-align:left; clear:both; }
.fbox {padding-left:3.0pt; padding-right:3.0pt; text-indent:0pt; border:solid black 0.4pt; }
div.fbox {display:table}
div.center div.fbox {text-align:center; clear:both; padding-left:3.0pt; padding-right:3.0pt; text-indent:0pt; border:solid black 0.4pt; }
div.center, div.center div.center {text-align: center; margin-left:1em; margin-right:1em;}
div.center div {text-align: left;}
div.flushright, div.flushright div.flushright {text-align: right;}
div.flushright div {text-align: left;}
div.flushleft {text-align: left;}
.framebox-c, .framebox-l, .framebox-r { padding-left:3.0pt; padding-right:3.0pt; text-indent:0pt; border:solid black 0.4pt; }
.framebox-c {text-align:center;}
.framebox-l {text-align:left;}
.framebox-r {text-align:right;}
span.thank-mark{ vertical-align: super }
span.footnote-mark sup.textsuperscript, span.footnote-mark a sup.textsuperscript{ font-size:80%; }
div.tabular, div.center div.tabular {text-align: center; margin-top:0.5em; margin-bottom:0.5em; }
table.tabular td p{margin-top:0em;}
table.tabular {margin-left: auto; margin-right: auto;}
td p:first-child{ margin-top:0em; }
td p:last-child{ margin-bottom:0em; }
div.td00{ margin-left:0pt; margin-right:0pt; }
div.td01{ margin-left:0pt; margin-right:5pt; }
div.td10{ margin-left:5pt; margin-right:0pt; }
div.td11{ margin-left:5pt; margin-right:5pt; }
table[rules] {border-left:solid black 0.4pt; border-right:solid black 0.4pt; }
td.td00{ padding-left:0pt; padding-right:0pt; }
td.td01{ padding-left:0pt; padding-right:5pt; }
td.td10{ padding-left:5pt; padding-right:0pt; }
td.td11{ padding-left:5pt; padding-right:5pt; }
.hline hr, .cline hr{ height : 0px; margin:0px; }
.hline td, .cline td{ padding: 0; }
.hline hr, .cline hr{border:none;border-top:1px solid black;}
.hline {border-top: 1px solid black;}
.tabbing-right {text-align:right;}
div.float, div.figure {margin-left: auto; margin-right: auto;}
div.float img {text-align:center;}
div.figure img {text-align:center;}
.marginpar,.reversemarginpar {width:20%; float:right; text-align:left; margin-left:auto; margin-top:0.5em; font-size:85%; text-decoration:underline;}
.marginpar p,.reversemarginpar p{margin-top:0.4em; margin-bottom:0.4em;}
table.equation {width:100%;}
.equation td{text-align:center; }
td.equation { margin-top:1em; margin-bottom:1em; } 
td.equation-label { width:5%; text-align:center; }
td.eqnarray4 { width:5%; white-space: normal; }
td.eqnarray2 { width:5%; }
table.eqnarray-star, table.eqnarray {width:100%;}
div.array {text-align:center;}
span.pmatrix img{vertical-align:middle;}
span.bar-css {text-decoration:overline;}
.partToc a, .partToc, .likepartToc a, .likepartToc {line-height: 200%; font-weight:bold; font-size:110%;}
.index-item, .index-subitem, .index-subsubitem {display:block}
div.caption {text-indent:-2em; margin-left:3em; margin-right:1em; text-align:left;}
div.caption span.id{font-weight: bold; white-space: nowrap; }
h1.partHead{text-align: center}
p.bibitem { text-indent: -2em; margin-left: 2em; margin-top:0.6em; margin-bottom:0.6em; }
p.bibitem-p { text-indent: 0em; margin-left: 2em; margin-top:0.6em; margin-bottom:0.6em; }
.paragraphHead, .likeparagraphHead { margin-top:2em; font-weight: bold;}
.subparagraphHead, .likesubparagraphHead { font-weight: bold;}
.verse{white-space:nowrap; margin-left:2em}
div.maketitle {text-align:center;}
div.maketitle{ margin-bottom: 2em; }
div.author, div.date {text-align:center;}
div.thanks{text-align:left; margin-left:10%; font-size:85%; font-style:italic; }
div.author{white-space: nowrap;}
div.abstract p {margin-left:5%; margin-right:5%;}
div.abstract {width:100%;}
figure.float, div.figure {margin-left: auto; margin-right: auto;}
figure.figure {text-align:center;}
figcaption.caption {text-indent:-2em; margin-left:3em; margin-right:1em; text-align:center;}
figcaption.caption span.id{font-weight: bold; white-space: nowrap; }
p + figcaption, img + figcaption{margin-top: 1em;}

and current.css:

@import "main.css";
#TBL-1-1{border-right:1px solid black;}
  • This looks like the best available solution to the problem. Thank you very much!!
    – qarabala
    Oct 9, 2022 at 13:15
  • 1
    @CebişMellim you are welcome! I hope it will work, let me know if there are some issues that I didn't anticipate.
    – michal.h21
    Oct 9, 2022 at 13:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .