Make4ht generic css

make4httex4ht

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.

Best Answer

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)
  end
  os.exit()
end

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

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

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

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

if not main_file or not secondary_file then
  help()
end

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

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


-- 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)
    end
    used[line] = true
  end
end

-- 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 )
  end
end

main:close()
second:close()

-- 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"))
main:close()

-- 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"))
second:close()

print("Done!")

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{margin-top:0;margin-bottom:0}
p.indent{text-indent:0;}
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; }
img.math{vertical-align:middle;}
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%;}
img.cdots{vertical-align:middle;}
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.minipage{width:100%;}
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;}
.reversemarginpar{float:left;}
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.eqnarray{text-align:center;}
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;}
h2.titleHead{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%;}
.abstracttitle{text-align:center;margin-bottom:1em;}
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;}
.abstract{margin:1em;}
 

and current.css:

@import "main.css";
#TBL-1-1{border-right:1px solid black;}