It feels that html and css are more configuration than code when writing an average webapp. This often manifests as a kind of write-only nature of html and css. In addition debugging these parts of your app is most difficult.
Dictionary defines configuration as relative arrangement of parts, or as functional arrangement. When considering applications or computer systems, this would mean the kind of composition that is achieved by using the system under configuration. For example HTML and CSS define the kind and style of predefined components that form a web page whereas backend software’s configuration would be where to find a database server and how to connect to it. A typical feature of this kind of configuration is that the configuration is written as is and does not provide any executable features such as loops.
Typical web frameworks try to solve this problem of generating configuration for the browser but they fail to regard this inner nature of the problem and rather view a web application as some kind of state machine which tightly integrates with DOM. Good examples of this are Angular directives and web components that basically ship independent pieces of configuration to your browser. Afterwards you can programmatically integrate these into your application but the problem remains that your UI is represented as configuration.
Typical configuration formats such as JSON, XML and by extension HTML and CSS suffer from the lack of programmability. What you write is what you get. There is no support for loops or any other kinds of comprehensions within these formats. In addition, there either is no validation (e.g. JSON) or validation is horribly complex and still ineffective (e.g. XML). Others have realised this problem too and Google has released Jsonnet that extends JSON by providing templating, loops, etc and can be compiled into standard JSON.
This abstraction can be extended into other programming languages too. Clojure is one example of a programming language where every is expression is a value. This allows us to write a literal representation of our JSON configuration and output it into proper JSON. In the following example I define a simple JSON file using native clojure data structures and functions. This is then executed with relevant parameters and passed to a standard JSON encoder. This gives us a programmatically generated JSON which closely resembles the original clojure data structure but lacks the expressive power that was inherent in the clojure version. However this proves that it is possible to use powerful programmatic tools to produce configuration.
So how can we move forwards and embrace code over configuration? New web technologies are already embracing this change in thinking. JSX moves HTML and CSS generation inline with your application code and effectively turns HTML into a programmable language. Web components allow encapsulation of HTML and CSS into components and thus enable abstraction. When it comes to other modes of configuration, such as JSON and XML, it might be a good idea to generate the configuration from some other format. Programs such as Vagrant have already demonstrated that configuration is easily doable as code.
There are some limitations though. If you need to change your configuration in a live production or environment, the necessary development tools might be unavailable. In addition, if your configuration change in code needs a recompilation, this is very likely to be impossible too. However containerization and other modern ways of deploying software have greatly reduced the need to edit configuration files on servers. Rather the editing of configuration is done through deploying the application again. This allows editing the code/configuration using editors and IDEs that actually support your programming language.