forthebadge forthebadge Gem Version

This gem was last updated on the 10.03.2024 ( notation), at 15:36:44 o'clock.

Introduction to the Cyberweb project

The cyberweb project allows the user to make use of ruby to tap into web-related functionality in general.

Use cases herein include running ruby in oldschools .cgi script, as well as via sinatra-applications (including storing the code in plain .rb files) or RubyOnRails-applications.

Future goals include offering at the least the very functionality that can be found in webmin ( as well as in wordpress ( - stay tuned for this in the coming months and years.

Installing the cyberweb gem

Use the following commandline instruction to install the cyberweb gem:

gem install cyberweb

Alternatively simply download the .gem from the official homepage, at -

Requiring the Cyberweb project

After the cyberweb project has been installed (see the section above this paragraph), you can simply issue:

require 'cyberweb'
require 'cyberweb/autoinclude' # This is the preferred and recommended way for .cgi files.

If you only need certain functionality then you should require the relevant parts as-is; you can also look under the cyberweb/requires/ subdirectory, where common use cases for require-statements, in regards to the cyberweb project, are kept.

The (slightly convoluted) History of the Cyberweb project

The following rather lengthy paragraph shall explain some aspects related to the history of the cyberweb project.

The cyberweb project was created a very long time ago, in about the year 2004 or so - give or take. Back then it was written exclusively in PHP.

I was combining custom functions (in PHP) to control how to serve web-related content back in these days. Mostly the use cases that I had were related to serving local content, that is, different .php files to be served, as well as some local text files. A few of these .php files were hosted externally, though, just to showcase the feature set.

In late 2004, sort of, I transitioned into Linux as my primary operating system. Along with this transition I also started to use Ruby, which eventually replaced PHP for my needs.

The original framework (the ancient code for the cyberweb project) was written (and maintained) in PHP and this origin is in some ways still somewhat similar to the cyberweb project. To illustrate this statement specifically: the original class Cyberweb::WebObject was written at about the same time, in the year 2004, in PHP - or perhaps a year after that, in 2005.

class Cyberweb::WebObject had a smaller use case back when it was written in PHP - less code and fewer methods, but by and large I already had the idea back then to describe a web-site in PHP completely. That is, to generate its content purely via PHP as-is.

I eventually abandoned PHP, as pointed out above, and I went on to rewrite the parts I was using in PHP in ruby. The functionality that was initially part of cyberweb thus originated from a legacy use case. The original use case for class WebObject was to actually describe a web-object, similar to a .html file, but dynamic and adaptable in nature - a higher-order class. A .html page can be generated from an instance of class WebObject, for instance. This use case still remains with the cyberweb project and it existed in the old PHP code too: I want to be able to autogenerate .html pages via the cyberweb project. Of course there are additional use cases, but this is an example of legacy-derived use cases.

The Cyberweb-project was rewritten several times over the next ~15 years or so - actually 18 years since then. Quite a long time ago already.

Today the Cyberweb-project is not quite so similar to the old code base that was written in PHP anymore. The important core methods, though, are still somewhat similar. Let's illustrate this statement with a specific example.

I was using div() in PHP already, as a function call. I am using the div() method in ruby too, through cyberweb, even though a separate project (HtmlTags) is nowadays tasked with autogenerating HTML tags. It was easier to separate this functionality into a separate gem. But, as this example shows, it originated from code I wrote in PHP.

Ruby allows for significantly more functionality and flexibility out of the box than PHP does, so I can do the following in Ruby just fine, by default:

div {

In PHP this is not easily possible, because the syntax is more rigid; there are no blocks in PHP, for instance, and you need to carry with you the () to arguments. I find ruby in general more flexible and better than PHP here, but your mileage may vary.

Let's revisit the syntax consideration shown above, via the div {} syntax. I consider ruby to be the better language here, when compared to PHP, as we simply have more flexibility syntax-wise, which in turn helps when we wish to formulate ideas into code (and projects).

This flexibility really helps a lot when writing more dynamic, and more succinct, code. We can define custom DSLs (Domain Specific Languages) that are close to the target area we operate within. See Ruby on Rails and the various active-gems as one example of this flexibility. These allow us to store data in databases in a very expressive manner. You can, of course, reason that complexity should be avoided, but at the end of the day we need to consider the totality of the situation: does that flexibility make us human beings more productive and efficient? I think the answer to this is either yes, or, at the least, it can be - whereas, if you look at PHP, you simply have less flexibility, and, in my opinion as a consequence of this, fewer options.

Going back to the transition phase, where I switched from php to ruby, the cyberweb project was renamed several times as well. The first renaming was done towards web_foundation, then I renamed the project towards cybersprawl, then to Cyberweb, then to web_object and finally back to Cyberweb again. A bit chaotic this is ...

I think the name Cyberweb is the best choice among these alternatives, though. With that name I want to capture "the future" - that is, ideas where web-apps are more integrated and powerful in general. A bit like how Alan Kay envisioned the world wide web. At the least this is a far-away vision to have; perhaps webassembly brings us closer towards that goal. For the time being, we have to use HTML, CSS and JavaScript for the most part of course.

While web_object is the more technically correct and accurate term, as everything related to the www is handled via that object (or such objects), I prefer the name Cyberweb for the whole project - it sounds rather futuristic.

The name WebObject is a good name too, though, as we attempt to describe a particular "web-page" as a "web-object", with specific functionality, basically. The WebObject not only describes the raw HTML code or combines it with CSS and JavaScript, but it can be thought of as a higher abstraction in the hierarchy. In principle we could generate a .pdf file from a WebObject too, so the functionality is not limited to "merely" HTML or CSS only. This is another goal for the project, but it is secondary - still, I want to be able to have a .pdf page too, derived from a .cgi page, a .sinatra page or a .html file.

class WebObject was originally the very main class I was using in PHP to describe my local knowledge base, an "app" where I kept useful information bits about linux, and ruby, and other parts together. The code for this project in PHP was simpler, and also uglier though, and less flexible. (Actually the name was not even WebObject back then, but let's not make this too overly complicated and convoluted; it's already a fairly messy history.)

This knowledge base resides in another gem I maintain, called roebe. This is a separate project, but in order to view the various web-pages of the roebe gem, the cyberweb gem will be needed. (The roebe gem is my primary gem - I use it as a general entry point to all my code. The cyberweb gem is less specific to my use cases; other people could use it just fine for their own web-specific projects, but I have to caution other users in that, despite this, the cyberweb project is primarily catering to my use case. I will try to make the project more flexible for other users too, but it is not necessarily a primary goal of this gem to "appeal to the masses".)

When I switched to ruby, I rewrote all my PHP code in ruby, as stated already; and eventually I did put the web-specific parts into a project called web_foundation, which was the actual predecessor to Cyberweb, as mentioned as well. Cybersprawl was a component of this back then. The initial idea here was to have cybersprawl be the basis for a custom webforum. At a later time, this changed a bit and was extended - cybersprawl not only tries to include a webforum, but also clone all the functionality available in webmin. In other words, to be usable as a webmin clone. This is far from finished, though, and I may never finish - but, even then, this use case remains, so who knows. Perhaps at a later moment in time I can succeed with that goal. The wish to have a web-forum as part of the cyberweb project is still retained.

The original Cyberweb project on was "officially" started on 13.06.2012 (13th June in the year 2012) - that is, the name was first used in the year 2012. In 2020 it came to an end and was replaced with the WebObject project, but in May 2021 the original name was reinstated again. Such a messy history for the win. \o/

The project called html_tags was created at about the same time back then, in the year 2012, in order to keep the code base of the newly generated project somewhat cleaner and smaller. WebFoundation was thus renamed to Cyberweb - the original directory that kept the code there was put under the directory called foundation/. Old gem releases of cyberweb may still show that, back when I kept these old releases on

In August 2018, the foundation/ subdirectory was removed and the code residing therein put into other parts of the cyberweb project instead. The original functionality that WebFoundation provided was retained.

The transition phase in 2012 happened to some extent because I was still using ruby 1.8.x and had to make several changes to the old web-foundation project, in order to have my code work on ruby 1.9.3 anyway.

The rewrite would allow me to change some design decisions I made earlier on, which were not that ideal - in other words, to allow me to discard some of the old code at the same time (which again happened in 2018, when I cleaned up the cyberweb project, after many years of "semi-activity" only).

The rewrite step worked for the most part, even though it took me significantly longer than expected. While the code base that you can see today is still not "perfect", it is quite ok-ish and also to some extent documented this time - at the least much better than it used to be in the old code before. I will continue to improve the documentation slowly over time. Whenever I do a full or a partial rewrite, I make sure to improve the existing documentation, so one minor goal of every rewrite is to make the project's documentation better.

In my opinion, it is quite common to rewrite web-related projects in ruby in general - see manveru's old Ramaze project, for instance, which unfortunately was abandoned at a later time. (Innate was created prior to that

Essentially cyberweb integrates what I learned over the years, so I built some sort of "framework" for the web. It is actually not necessarily a framework only as such, but more a tool-set project for the www. There won't be a lot of idioms used such as could be seen in rails - because the cyberweb project is way too simple to make use of complicated idioms. You can even call the cyberweb project a dumb project, deliberately so, on purpose. I do not like the proliferation of complication and complexity that the modern web-era induced onto developers - just look at the amount of JavaScript frameworks that emerge and disappear over the years. Anyone still remember Mochikit? Or the era before Mochikit? Do we have to transition to these again and again and again? Why not abstract these use cases away for us?

The cyberweb project has combined, and thus integrated, the following older components that have existed at various moments in time or may still exist:

- web foundation
- Ruby-CGI (a snapshot, including the excellent cgi-exceptions functionality)
- cybersprawl
- sinatra mapping

This may not be hugely important to know, but it explains a bit of the historic origin for the cyberweb project.

The cyberweb project has a rich set of functionality by default.

Users can, at their own discretion, install additions gems, naturally. A few of these gems may enhance cyberweb in one way or the other.

PDF-related functionality is quite important in general, and this is the case for the cyberweb-project as well. It is recommended that users of the cyberweb-project should consider the installation of a PDF-related gem - be it prawn, or, more modern, hexapdf. More functionality may be tied and combined with .pdf files in the long run, as far as the cyberweb project is concerned, to make the cyberweb project a bit more polished in regards to a (viable) alternative to wordpress one day (in the future). Stay tuned in this regard.

Aim, Goals and Scope of the Cyberweb project

This subsection will detail some of the goals of the Cyberweb project.

Before describing the cyberweb project in more detail, please keep in mind that the project is fairly incomplete, not even in an early beta stage; and that it is presently catered to my own use cases, so it may not work for you. Consider it more as a proof-of-concept project than something you may want to use for production. Sinatra may be a much better choice for the latter.

At any rate, let's next see for the aims and goals of the cyberweb project - after all that is the primary purpose of this subsection.

The Cyberweb project is both a collection of web-related tools (thus, a toolset project) as well as a web "framework". Both terms will be defined next.

What is meant with a "set of web-related tools"? This means that there will be code, written in ruby (primarily), that aims to solve problems related to the world wide web, ranging from small to medium-sized issues.

This may also include formatters and linters for e. g. JavaScript in principle, but it can also include file-generators or related to managing files, directories, css files, javascript files, and so forth. A set of tools.

The other part of the Cyberweb project is to act as a "framework", that is - to provide code that can be used for higher abstractions when creating web-apps.

Note that the Cyberweb project itself is not necessarily extremely opinionated. Different strategies may be used, be it MVC (model, view, controller), be it plain oldschool .cgi or be it modern microservices and REST APIs as such, such as used in rack and sinatra/padrino. All can be combined and mixed together - in theory. In practice, Cyberweb is of course limited mostly by my own time investment, so different parts of the project will be more comprehensive (and better) than other parts. The bottom line is that there is "no single strategy to rule them all", as far as the cyberweb project is concerned.

It is true that the Cyberweb project is, in itself, very traditionally focused on the .cgi centric ways to develop web-apps. In theory, a .cgi page could also be thought of as a WebApp. Nothing prevents this really, other than some old assumptions about CGI.

In the long run, expect the Cyberweb project to become more general and hopefully more "modern" as well, as I work on improving the documentation in the next step (no possibility to have more users without high quality documentation).

Since June 2021 two new goals were added to this project:

  • It will contain documentation in regards to useful CSS knowledge.
  • It will contain documentation in regards to useful JavaScript knowledge.

There are two reasons for this. The more important reason was that I wanted to bundle web-related stuff into one project, and just use that project, rather than dilute this to many separate projects.

The second reason was that I have collected a lot of knowledge over the years about CSS and JavaScript, and wanted to keep them presented (and presentable) in a single project as well. This means that there may be pure CSS, pure HTML and pure JavaScript examples distributed within the Cyberweb project as well.

Since as of October 2023 you can also find a .html page that links to all examples. This file can be found at:


(Remember that you can simply extract a ruby .gem file; there the .html file can then be found.)

Features of the Cyberweb project

The cyberweb project attempts to address multiple different use cases, so it is difficult to provide an overview over its features; in part also due to its fuzzy history.

However had, this subsection will at the least try to name some of its features - keep in mind that ultimately it is about the use cases you may have that matter more.

In no particular order, the cyberweb gem attempts to solve these problems:

  • Provide support for rack, sinatra and .cgi files for "out of the box" working with web-related technology in general.

  • Provide numerous helper methods in various classes (most importantly in Cyberweb::Base) to help build web-applications.

  • Be able to generate standalone .html files.

  • Provide a unified DSL over web-related use cases.

  • Support CSS-related aspects, including auto-generation of CSS code and re-using CSS templates.

  • Aim to provide a webmin-clone.

  • Aim to provide a wiki.

  • Aim to provide a webforum.

And many more use cases that are somehow related to these goals.

Not all of these use cases currently work fully; the cyberweb gem in many ways is also there to help me experiment with different ideas, and try to see what could be done to make these work.

A word about "CSS templates": you can select various different default CSS templates. They will be stored in the cascading_style_sheets/ directory by default. To use them, pass a symbol to the method invocation for css_style=(). They are numbered in succession, so template1, template2 etc..

Example for this on the main w object:

w.css_style = :template1

This will default to the template1.

Alternatively since October 2022 you can simply use this, if you work with a WebObject:

template1 '
  # your CSS rules go in here

This will pull in the first template (template1) and then add the CSS rules towards that.

Currently the way to add new templates is to expand the case menu.

Adapting the cyberweb gem to your use cases

Presently it may be a bit difficult to adjust the cyberweb gem to your use cases. The primary reason for this is that the cyberweb gem was originally started to support my use cases, as well as making available images that I have collected over many years. So that explaines why the method img(), for instance, is defaulting to a fairly weird use case, which means that it may not work for your use cases initially. In the long run I intend to remedy this situation, but for the time being, you have to accept that some parts of the cyberweb gem are not useful for you.

Note that the above is no longer true since as of January 2023. I have decided, for several reasons, to simply distribute these images as well. They are available under:


You can also view these images via a dedicated .html file, at:


Some of these images are fairly old and require adaptations/changes, and adding these images has made the cyberweb gem significantly larger as well, which is not great - but I think the drawbacks are outweighed by the advantage that now every user of the cyberweb gem can use these images as well, without me having to offer separate download links. I collected these images over the last 20 years, and some are probably outdated at this point in time, but again - some images may still need to be tweaked, file sized decreased, simplified, and what not. I will do so over the course of the coming months.

I decided to add this subsection to document some things, and provide some help to new users, until eventually the situation improves so that people can just install the gam and "it will work", as-is.

Without further ado, let's clarify some things here next.

The cyberweb gem needs access to a temporary directory.

On Linux this is typically /tmp/. The cyberweb gem may create a subdirectory there, called cyberweb/, and then copy some files into that subdirectory - in particular JavaScript .js files. (If you have difficulties here, consider adding such a subdirectory there, with explicit permissions to allow people to dump data into that directory - after all that is the point of /tmp/ on linux.) If that step fails then you may have to copy these files manually for now; in the future this manual step may no longer be necessary, but as of May 2023 it still has to be done - apologies for that extra time investment.

To query the base directory in use you can call the following method:


If you want to use another temporary directory then you can use this method:


You need to make the permission bits on that directory possibly to be modified, such as /tmp/ on Linux normally is able to be modified by group and user nobody (or, the user that runs the webserver; in my case this is typically lighty, as I use lighttpd as my primary webserver).

The code for this functionality can be found here:


Or the direct require command:

require 'cyberweb/toplevel_methods/temp_directory.rb'

This is a very important first step to do, to adjust the temp directory to your use case.

I may add more code support for this step in the future; for now (October 2022) I just wanted to document this, so people know where to look for changes in this regard.

Include the cyberweb project on a website

To include the cyberweb project on a website, in your .cgi script for instance, do use this line:

require 'cyberweb/autoinclude'

You can then populate the @web_object object, which resides in the main Cyberweb-namespace, and which is also aliased through a convenience method called w(). If you autoinclude Cyberweb then you can use the w() method directly.

This allows you to describe a webpage, such as by issuing the following code:

w {
  title 'My first homepage'
  body_css 'mar1em'
  h2 'Hello World!'

Note that this should happen on separate lines - the description here for the gem does not replace newlines with the html

Inside w {} you can issue special instructions, such as use_jquery or disable_webimages. The former allows us to use jquery, the latter disables webimages. (Webimages are small icons that I find myself to use a lot. If you wish to use these images, have a look at


Proper (default) order of arguments to many methods in the Cyberweb project

The Cyberweb project uses quite a few methods that have more than 4 or 5 parameters.

The typical order for these methods is the following:

(1) the content belonging to the tag at hand (2) the css class that is to be used for that tag (defaults to class WebTag) (3) the id to that HTML element (optional) (4) the css style for that tag (optional) (5) javascript code to that tag (optional)


The method Cyberweb.set_path_to_images() can be used to set the path to a global image directory, that is - a directory that holds all images. On my home system this defaults to /home/x/data/images/, so if you find any references to that directory in any of my projects then this is the reason as to why, since it is the default on my home setup.

I put almost all images into this directory as-is, but there are a few exceptions to this as well. The important thing is that the cyberweb project has to remain flexible.

Note that this directory will only be of relevance if the configuration options for the cyberweb project were set up to use such a directory in the first place. Only image-related methods are affected by this setting anyway.

Note that Cyberweb.set_path() is a shorter alias to this method; may be useful in IRB. Otherwise I recommend to use the longer method name instead, as it is more explicit.

For many users this API may be fairly irrelevant or even cumbersome. In that case you should consider uploading some of your images to a remote server and then simply link towards these images rather than having to deal with paths to local images being a nuisance. I do that with some of my files, e. g. referring to a FTP site. In the long run, though, this situation will eventually improve.


If an image is not existing, but used within the Cyberweb framework, then a a red border and a red text will be displayed around that (non-existing) image.

This way, the user is being encouraged to fix the problem at hand.

However had, it may also be annoying to see it if the user can NOT fix/change this.

This is why the red warning or warnings in general, can be reduced or disabled - have a look at the configuration file for this. Personally I prefer a red warning, but others may not want to have this.

If warnings are set to verbose, then the cyberweb project will display the notification mentioned above for all images that were not found. If it is set to normal or lower than that, the cyberweb project will not display that warning.

Greek letters

The old greek letters are specified via shortcuts such as σ in HTML. The σ variant would display the small sigma character; the constant SIGMA_SMALL or just SIGMA will allow you to refer to this constant within the Cyberweb project.

You can output a table with all available greek letters by issugin the following command:


Commandline usage

A commandline program exists, at bin/cyberweb.

This file allows you to generate a new file-skeleton, such as via:

cyberweb foo.cgi
cyberweb index.cgi

You can also get some feedback over what it can do, via "cyberweb --help".

The interactive web_object-shell

There also exists an interactive cyberweb-shell, which may be used to test out various things - but it is fairly unfinished, so I do not recommend anyone to use it as of yet (2018).

The idea is to have this work as some kind of developer-console where web-related activities can be tested.


Since as of cyberweb version 0.0.5, a dependency exists on a project called html_tags, which was created in order to separate the generation of HTML tags out from the rest of the framework.

The idea is to hold a full HTML page in a special object, the so called "web_object", and to then .serve() said object when it is required. Which essentially is done through a .cgi page.

Since as of April 2019, the old .cgi approach will be extended; while .cgi will be always supported in the Cyberweb project, an approach similar to sinatra will eventually be adopted as well.

Configuration - and editing the configuration file (which is a yaml file)

Keep in mind that you can modify a lot of the configuration that the Cyberweb project uses, through the yaml files stored in the configuration/ subdirectory.

If you need to display the configuration settings via web-page, you can always use the method .show_config(), on the main Cyberweb, such as via either of the following code:

div('mars3em') { w.show_config }

You can also just show the configuration setting without depending on the web-object, through this module-level method:


The main configuration file, a .yml file, can also be modified through a commandline "interface", via:

cyberweb edit

This presently uses a hardcoded value (towards the editor called vim).

You can also query the current configuration via appending config? such as in:


HTML Tables and the Cyberweb project

The method table() is the primary entry point for table-related tags. The first three arguments are:

css class to use
ID of the table
css style to use

You can also, optionally, pass in a dataset to the table, such as an Array, via a block argument.

The following example shows how to do that:

table('mars1em','test_table1','border:1px solid rand') { %w(
  this is a test table1 with every individual
  entry becoming populated into the table

The part after the {} constitutes the Array that is passed into the table.

By default this will use two td-elements, aka table data elements. The third element goes on a new line, aka via a closing tr tag (in HTML parlance).

Note that you can use variants of table() if you need a different amount of td tags.

For example, table4() can be used to denote a table with 4 elements per row:

table4('mars1em','test_table1','border:1px solid rand') { array_goes_here }

You can also set global CSS classes to class Table:

Table.set_css_class 'bblack5 pink_border3 marl2em mart1em'

For a longer explanation of that .set_css_class() functionality, have a look at the link here at HTML Tables and the Cyberweb project.

Note that you do not have to supply any arguments to table() aside from the dataset given into it as block - a simple Array will suffice:

table { pass_array_here }

You can also style each td element, such as by tagging them with a block border:

Td.set_css_class 'bblack1'
table('mars2em') { %w(
  This is just an example Array
Td.set_css_class ''

The last line of code will again clear the default set to Td.

The name cyberweb

You may wonder why the name used to be cyberweb.

There is not a single good reason for this other than, firstly, I thought it was related to the web - so I included web. And cyber? Well, I like science fiction; and cyber sort of fits to the www too, at the least to some parts.

The idea for a "social" web, from the point of view of the older web-foundation project (the predecessor to the cyberweb project), was to call this the "cybersprawl". The name cybersprawl would indicate a virtual meet-up place for people.

This may sound a bit confusing but it is sort of how the name gradually evolved - and eventually became cyberweb, before it was renamed to web_object in 2020. And at a later time back to cyberweb - yup, I change the project names way too quickly. But the name used to by cyberweb in the past, so I am slowly getting used to that name.

HTML Entities

If you wish to remove HTML entities from a given input string at hand, you can use Cyberweb.escape_html() or one of its alias.


Cyberweb.escape_html('abc') # => 'abc'
x = '<p>this is (&nbsp;) a test</p><div> Ok -&amp; outcome will be </div>'; y = Cyberweb.html_entities(x) # => "&lt;p&gt;this is (&amp;nbsp;) a test&lt;/p&gt;&lt;div&gt; Ok -&amp;amp; outcome will be &lt;/div&gt;"

Specifying a monospace font to use

The Cyberweb has a method that allows you to use a monospace font.

Within your Cyberweb instance, such as:

w {

You can add any of the following two lines:


This will use a monospaced font. I needed this functionality because I sometimes use the pre-tag, and display numbers in a table-fashion, for where it may be useful to use a monospaced font, so that the alignment of the text is easier.

The WebObject (Cyberweb::WebObject)

The following subsection will contain information pertaining to the most important class of this gem: WebObject.

This is the primary class that is used for describing a web-application (or, in oldschool parlance, a HTML object or HTML page).

Setting the date-of-creation for a web-app based on WebObject

Since as of October 2021 you can use:

created_when '20.08.2021'

To indicate when the webpage at hand has been created. This will then add a meta-element to the page, which is roughly equivalent to:

<meta name="DCTERMS.created" scheme="DCTERMS.ISO8601" content="2010-03-17T13:31:50"/>

I am not sure whether this is super-useful or not, but I wanted to add a method that keeps track of the creation-time of web-apps based on web_object, which is the main reason why this functionality was added. At the least it helps me remember when a web-app was created.

The default styling for a-tags in HTML is to start with text-decoration: none, and upon a hover event change towards text-decoration: underline.

Since this is so commonly used, the method .default_hyperlink_behaviour() can be used to add the CSS rules for this, as-is.

Setting a title on a webobject

You can set a title on the default webobject via:


You can omit this call, in which case we will default to the filename of the page in question, such as for a file named foobar.cgi, the corresponding title would simply be "foobar".

You can also use markdown files if you want to. I personally use a file such as or The method call will try to read in the file content, and then use that as the title, if the file exists.

The default image directory

The default image directory is defined in default_image_directory.yml

At least the name of the image directory.

Viewing the source of a webpage

Use the view_source() method to add a javascript button, to view the source of a page. The method view_source() is defined in the file cyberweb/web_object/misc.rb:.

You can, of course, combine this with other code elements. For instance, if you want to embed the view-source button into a div, and style it, then consider the following:

div('BG_Black white','div_view_source') { view_source }

This will create a div-tag with black background and white font colour, and the id of that div will be div_view_source. Inside that div-tag the view-source button can be found.

The table-tag

The tag that is generated via table() will create a HTML table. It also supports blocks. That means you can use arrays in tables as input, such as shown in the following example:

table { %w( one two three for ) }

Or, styled with CSS:

table('s1em bblack1') { %w(one two three for) }

You can combine fieldset with table and a caption, by doing:

table_with_caption('title of caption goes in here')

Hiding / disabling scrollbars

You can use:


in the main web_object to hide the scrollbar, by making use of CSS. I recommend against this, because it may annoy some users, but it was enabled because sometimes there may be use cases to NOT have a scrollbar at all.

The idea was taken from:

Showing the source code of a particular file

By default every file that is part of the cyberweb project can show its source to the visitor, by appending:


to the URL.

For example, on my home system I make use of this like so:


Evidently this is not always wanted and will, in the future, have means to disable this (or selectively enable it in the configuration file). But for the time being (January 2020) this is the way how things work - after all, even with criticism about this functionality, it is a feature too.

HTML header tags

HTML has, by default, different header tags, starting with h.

For example we have:

<h1>This is h1</h1>
<h2>This is h2</h2>
<h3>This is h3</h3>
<h4>This is h4</h4>
<h5>This is h5</h5>
<h6>This is h6</h6>

The corresponding generator in Cyberweb is:

h1 'This is h1'
h2 'This is h2'
h3 'This is h3'
h4 'This is h4'
h5 'This is h5'
h6 'This is h6'

If you also wish to make the content displayed there as the id="" setting, then you can use:

h1_id 'This is h1'
h2_id 'This is h2'
h3_id 'This is h3'
h4_id 'This is h4'
h5_id 'This is h5'
h6_id 'This is h6'

The id at hand will be the content, so this is more useful for short header-entries, such as "Goals" or "Aims" or "Introduction" and so forth. The latter functionality purely exists due to convenience - I wanted to quickly generate the default id entry for a sitemap.

Note that at the least h2_id() has been improved a bit, directly and indirectly, in January 2023.

Specifically the following is now valid:

h2_id('Stickstofffixierung - eine symbiotische Beziehung, als '\
      'Teil des Stickstoffkreislaufs') { :clickable_image }

So, what does this do?

First, as normal, it will "autogenerate" the corresponding ID entry, via the newly created method .sanitize_this_id(). I intend to re-use this method for all other parts of the cyberweb gem that require autogeneration of valid ID tags.

But, even more importantly than that, the block and the Symbol called :clickable_image, will now add an image (a small dot) to the left side of this header. This image is clickable by the user. If the user clicks on that dot, he/she will be re-directed to that specific header as intralink. In other words: this functionality allows us to "tag" any paragraph as intralink, by clicking on it.

I needed this functionality for many different local websites, so I thought it was more useful if it is made a proper method as-is.

Redirecting to another page

You can combine BeautifulUrl, and Cyberweb, to redirect to another page.



This would redirect me to my local todo-file in ruby. In fact: that was the primary reason why the code was added, so that I can use the web-server as a pseudo file system.

Evidently not everyone may want this feature, so in the long run this may have to be modified - but for now it will remain as it is. It can be used to quickly "jump" to another page, both a local page or a remote page.

If you want to do so via the meta-tag, consider using the following method:

Cyberweb.return_meta_redirect ''

This would yield the following string:

<meta http-equiv="Refresh" content="1; URL="">

Viewing the content of any file

You can view the content of any file via:


This can be disabled since as of May 2021, by setting the view_file: true in the project configuration .yml file. I recommend to do so, as you probably don't need this functionality. I needed it for my local webserver, to quickly test things, and view local files in the browser, no matter where they reside (which is handled by another gem, which is not published, as it is for internal use only).

You can use the dropdown() method to use several <select> statements, if you use class Cyberweb::WebObject.

Specific usage examples:

dropdown( %w( a b c ) )
dropdown( %w( a b c ) ) {{ selected: 2 }}
dropdown( %w( a b c ) ) {{ selected: 3 }}

The middle variant will have the second entry selected as default; the last variant will have the third entry selected as default.

Note that for the purpose of dropdown() we will begin to count at 1 rather than 0. So 1 refers to the first entry. Furthermore if the number given to selected: is too high then it will be automatically reduced to the last entry of that Array - this should simplify using the method a little bit.

For a working example of the method have a look at the file testing_the_select_tag.cgi.

Here is also a small screenshot with a bit of CSS styling to show how this looks:


The method Cyberweb.display_all_files_in_this_directory() can be used to simply and quickly display the content of all files in the given (target) directory.


Cyberweb.display_all_files_in_this_directory '/tmp'

I needed this functionality because I had many standalone .py files holding matplotlib code and I needed to display them, so this functionality was added in May 2020.

Register on-click events

If you want to register an on-click event and change the opacity value of an element, you can use this method:

on_click_change_opacity '#drag_notepad','0.95'

The first argument is the ID of the target element, and the second value is the opacity value - the lower that value is, the higher the opacity (and thus, the highlighting).

Note that you can also combine this with a drag-action. For instance, the symbol :drag_and_highlight means that we will combine both actions here, thus allowing a drag-object action, and also a on-click-highlighting action on the same object.

Body id

To set a body-id for the Cyberweb, you can use something like this:

body_id 'foobar'
set_body_id 'foobar'

This is equivalent to:

<body id="foobar">

Not a huge saving per se, but if you just want to keep a separate entry for the id of the body, you can use this method on a web_object instance.

Editable text

HTML5 allows the visitor to modify text on a webpage (although not persistently).

The Cyberweb project also allows this. Example:

e('Type something here.') { :editable }

This would make a span-tag, following by a br-tag, and the attribute that this is editable. You can select some text and then just type as-is - and thus modify the text.

Caret cursor in CSS and cursors in general

You can style the colour of the cursor that appears in an input-field.

Example for this:

.input_field {
  caret-color: tomato;
  font-weight: bold;
  font-size: 30px;

If you need a specific example, have a look at the following file:


This may then look like this:

The relevant part is the red cursor in the ~middle in that input field.

If you have a use case for a web-page having some different cursor, you can use this for a given Cyberweb::WebObject:

cursor :wait        # signals that the program is busy.
cursor :help        # signals that help-information is available.
cursor :crosshair   # signals that a selection is possible/needed.
cursor :grab        # signals that this element can be grabbed via the mouse/pointer device.

CSS helper code and how it relates to the Cyberweb project

This subsection attempts to detail how the cyberweb project relates (and makes use of) CSS.

All my custom CSS rules are distributed in the subdirectory called cascading_style_sheets/. You can find files such as colours.css or default.css and so forth. Furthermore I have a local directory at /home/x/data/CSS/ which contains symlinks to the subdirectory cascading_style_sheets/. This was done mostly because it saves me some typing-work on the commandline.

CSS can, in principle, be accessed through the predefined global object named @css.

This object can be accessed via "css" or via the helper method called css(). (Remember that you can omit the () in ruby).

A specific usage example would look like this:


The idea here was that we could treat all the CSS code in any given web-app as an object too, and manipulate it if needed.

Additionally, we would also be able to modify default CSS assignments given to some methods, redefine them and so on.

Do note that since as of 2020, I am no longer as convinced that this is really that useful. So consider this a bit of work-in-progress rather than a finished solution that other people should use.

For instance, to change the default for the HTML tag h4, the following code could be used:

css.h4.custom_css = 'padl1em'

The idea here was to be able to re-define which custom CSS class is to be used. (padl1em is my abbreviation for padding-left: 1em)

An alternative syntax exists as well - this is the better way, in my opinion, and should be used:

Table.set_css_class 'bblack5 pink_border'
Div.set_css_class 'mar3em'

I personally like explicit setters like the above, but the following variants are equivalent:

Table.css_class = 'bblack5 pink_border'
Div.css_class = 'mar3em'

Future goals for the Cyberweb project

There are a tons of things I always wanted to add or have available in a web-toolkit - a simple webforum; a blog engine and system for managing the content therein; the possibility to easily scrape remote websites, with code that is simple to understand, write, use (via a web-interface) and maintain. And many more goals - in short, to use the browser as the main tool.

Inertia and laziness is one (or two) reason(s) why these goals have not yet been implemented, largely because I find myself facing non-web related issues more often than web-related issues. So naturally, more of my time goes into non-web related issues. Furthermore, I really dislike JavaScript - if only we could describe everything via Ruby instead ...

For the design of the Cyberweb project (and I am aware that a LOT of it could be improved here), I am wondering whether it would not be better to actually replace all of the dichotomy out there in regards to the www, with "one language to rule them all" as a solution. I don't even refer to ruby primarily as such, even though Cyberweb is evidently written in ruby - but what I mean is ... consider the following ...

Why do we have to write JavaScript? Why do we have to write CSS?

Why can't we let our computers actually generate the "logic" behind these programming languages or markup languages?

For example, take:

set_font 16

This could mean a (any) font with 16 pixels in size.

It's quite simple to use this from within Cyberweb:

w {
  set_font 16


We could even get rid of the '_' there perhaps:

w {
  set font 16

Don't mind the "set_font" name; we could easily use this (or allow several aliases):

w {
  fontsize 16


w {
  font size 16

(The w is a shortcut to tap into the web-object instance.)

The primary thing of note here is - why would we HAVE to use CSS in order to style a webpage? Why not use, in this case, Ruby? Or any other language for that matter? Ideally one language to describe all these disparate languages (HTML/CSS/JavaScript) and the logic found in them.

Based on this thinking, when you apply this on everything, including JavaScript, you actually should be able to write something that is simple and works - and have ruby interprete it correctly. Or perhaps another language, similar to how LLVM works or perhaps the WebAssembly project, to some extent.

So, for example:

on_mouse_click highlight_id('mouse_pic')
on_mouse_click highlight_id(:mouse_pic)

Now, if you as the visitor are to click on this, say, a button or some other container element, you would highlight the element that has the mouse_pic id. This is quite easy to do via jquery as-is, but why even have to think about JavaScript at all?

I would like to have a platform where I can do simple manipulations, without having to worry about the underlying code implementation AT ALL.

So, this would constitute one future goal for web_object - to be able to do tasks, from Ruby, and have it applied to the whole Cyberweb component.

Note that WASM is in some ways a bit similar to this, in the sense that we become less dependent on JavaScript than before, since we can also use other languages. Of course this is still a far cry away from using just one format to describe everything, but still, it helps break up the monopoly of JavaScript, which is good that this happens. That way we aren't as imposed by the constraints that JavaScript puts onto us here anymore (in theory, at least).

Saving (storing) the content of the main web_object into a local file

You can save the main string into a file quickly, by using:

save # or web_object?.save

Note that this will save into the temp-directory. Your webserver needs to have access to it, as otherwise no file can be saved.

It may be simpler to use the last option, because of the main doc {} clause that is only finished after the w {} has completed.

That toplevel web_object? call taps into the main web-object.


Favicons are small images that may be shown in the tab of the browser. I consider them potentially cute and even useful, as it may allow the user to quickly look for specific images through the browser-tabs.

According to this blog all among the major browsers will request a favicon, even if one has not been set. This evidently wastes a tiny bit of bandwith.

If you wish to avoid this then you can simply inline a favicon. The smallest "inline" favicon which which ensures zero HTTP requests is the following:

<link href=data:, rel=icon>

You can do so in Cyberweb too, as part of the Cyberweb class, via:

favicon :inline
favicon :minimal
favicon :none

Use any of these three variants and it will lead to the above minimal "inline" favicon. This is admittedly not too overly useful, but the functionality was added nonetheless simply as a proof-of-principle. And, who knows - perhaps the web_object project will one day also offer support for "minimal webpages".

rem units in CSS

In the past, the em unit was quite popular in .css files.

Since some years, such as 2011, rem units are increasingly more popular - see articles such as

I have not yet decided whether to use rem units or not, but I am aware of the differences. I may be too used toward em to transition into rem, and add more complexity that way - but for the time being (August 2020) nothing changes in this regard.

The td_row() method

The Cyberweb project has support for <td> tags, via td() method calls.

Since inputting an Array of values padded with a td-tag is quite tedious, the method td_row() was added.

An example may be simplest to demonstrate this method:

td_row( %w( 256 128 64 32 16 8 4 2 1 ) )

This will generate valid td-tags for each of the given Array member, thus shortening the HTML code generated.

The WebImages components

WebImages are essentially just a small component of the Cyberweb project, available under the namespace Cyberweb::WebImages.

Since as of July 2020 the web_images component resides under the subdirectory at web_object/images/.

WebImages provide a way to map certain symbols, such as :big_star or :rainbow_circle, to a corresponding image.

To give another example for this: the symbol called :alert could be interpreted as showing a small icon that is useful for notification towards the end user. This is usually tied to a particular image, which is displayed on the webpage.

In the past, up until September 2020, these images were not distributed with the web_object gem for various reasons - one was that the .gem would become quite bigger. In September 2020 this approach was changed, and the WebImages are now also distributed as images. Some of these images were autogenerated via ruby code; others were "hand"-drawn in photoshop, kolourpaint or gimp, and others were re-used from permissive sources/licences. The licence for the images is different for the code: CC BY 4.0 (Attribution 4.0 International; see the following URL ).

Do note that even prior to September 2020, in May 2019 I modified the prior assumption that no images are bundled within the web_object project slightly - some images were distributed within the web_object project, but not as an "actual" image; instead, they were (and still are) available as base64-encoded Strings. The following subsection describes how to make use of such base64-encoded Strings.

First, we have to limit the above statement - not all images will be distributed as base64-encoded Strings, only those that may be somewhat useful to lots of different people. Simple elements such as a dot, or an arrow-image - the latter could be used to indicate which hyperlinks could be clicked on a website, for instance. (You can also use the Unicode symbols in general, of course, which does not require any .png file or base64-encoded String. In some ways, Unicode has actually made it a lot easier to work on web-projects without needing to bundle specific images as such.)

Note that some websites claim that Base64-encoded Strings load up faster than e. g. loading up .png files. This may or may not be the case, but what we do know is that base64-encoded strings will be somewhat larger than the corresponding binary image. So I think this statement about a speed gain is really only true for smaller images at best - which is an advice that is repeated on the www in general, small is beautiful, and fast. So we will limit this approach mostly to smaller images in this context; this makes it a bit simpler to distribute the web_object gem as well.

If you want to see the available images, you can use this method to help you:


In September 2020, this would tap onto this Array:


So, 15 images are so far made available as base64 string-encoded images.

Note that the images can be found under this directory:


Unfortunately a major design constraint (aka a major bug) was discovered on 18.09.2020 (September 2020), leading to the reversion of this change. I may at a later time re-evaluate this; in the long run I really want to include these images too, by default. But since that change broke a lot of code in my own web-apps, I had to revert this for the time being. This will eventually be fixed, but it requires some larger rewrite, and I don't quite have the time commitment for this right now (it will include some architecture changes in the web_object library as well).

In June 2021 experimental support for arbitrarily converting image files to base64 strings was added to the Cyberweb project. This currently depends on imagemagick, so make sure to install it first. This is highly experimental, so do not yet use it. The idea is that we will simply convert any image to base64 if the user wants to do so.

The API currently looks like this:

img_base64 'STD/ZAUBERHUT.png'

This refers to my base directory for images; and then the path within that base directory.

This is currently only tested on my home system. At a later time I'll add support for any image-conversion, and most likely a cache system, to not have to decode all these images again and again and again. Instead, to just convert it once; right now Cyberweb always converts this, as that was easier to do in code.

You can also make this image draggable via:


The Application Root

A typical web-related project needs to define and designate the starting-point directory. This is often called the "application root". The Cyberweb project will also refer to the base directory as the application root.

Presently Cyberweb uses a hardcoded approach mostly (sorry), but eventually it will transition into a more flexible approach.


Buttons are user-elements that can be clicked.

The following should work, in principle:

button {}

My long-term goal in regards to the above is to make this DSL work in web-applications as well as in 'traditional' toolkits, such as the ruby bindings to GTK (ruby-gtk).

A box-shadow effect applied to a button may yield to a depth effect for that button.

An example for this follows:

box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);

See also the file at cyberweb/examples/html/buttons_example.html to see differently styled buttons in action.

How to vertically align any element via CSS

You can use:

display: flex

display: flex specifies a Flexbox layout for the element.

You can also use align-items: center, which would take care of the vertical centering in a container-element.

The CSS property shape-outside can be used to allow geometric shapes to be set, in order to define an area for text to flow around.


.shape {
  width: 500px;
  float: left;
  shape-outside: circle(50%);

You do not need to use the flexbox, though. An older way is to define three div elements, such as by using these CSS classes:

.left {
  display: inline-block;
  width: 30%;
  height: auto;

.middle {
   display: inline-block;
   width: 30%;
   height: auto;

.right {
  display: inline-block;
  width: 30%;
  float: right;
  height: auto;

Use the variant that more suits your way to think about things. I actually prefer the oldschool div-CSS approach and avoid flexbox altogether. Keep it simple! \o/

This is not equivalent to a grid, though, in particular if you want a layout such as 3x3. In that case I recommend to use a grid. Example for this can be seen here:

Working with Frames

You can use Frames.

This example shows how, in the main frame:

w.frame_left 'foo.cgi' # specify frame to the left w.frame_right 'bar.cgi' # specify frame to the right w.use_frames w.serve

Working with Grids in HTML/CSS

You can add padding between the grid containers using grid padding or row-gap and column-gap. This is a general CSS feature implemented for Grids specifically.

Examples for that, in particular the two last lines:


row-gap:    6px;
column-gap: 6px;

Colours and the Colour chart in the Cyberweb project

If you wish to show a HTML colour chart, you can use the following method:


If you want to return a random HTML colour, as a String, you can use this toplevel method:


Show directories

If you wish to display directories from somewhere, use the method:


Predefined methods

  • Some commonly used methods are predefined, such as:

    question() answer() frage() antwort()

This is mostly because I use them quite often personally.

They are defined in:


Disabling web images

You can disable the webimages component even in an URL by issuing:


Of course you can also disable them through a configuration setting, in the configuration file - see the other command "cyberweb edit" how to edit that file. The idea is to allow several ways to achieve the same effect.

Modifying the configuration of the cyberweb project

The configuration is stored in a single yaml file. This file can be edited by issuing:

cyberweb edit

For a full listing of options, issue:

cyberweb --help


cyberweb HELP

The base directory

The base directory can be defined through the yaml file, with the entry called base_directory.

Standalone .cgi files

You can load standalone .cgi files, by supplying the path to the .cgi file in question.

Be careful however, we will use eval() to load that code.

Usage example for this:


or the alias:

run_cgi 'bla.cgi'

Support for markdown

You can use markdown formatting via the method markdown().

Example how to use markdown:

markdown(i = '/home/x/data/PC/MARKDOWN/')

Tables with alternate backgrounds

You can use tables with alternate background such as by doing the following:

Table.alternate_backgrounds(%w( one two three four ))

The following partial screenshot shows how this may look like, via an additional black border, to indicate where the table begins and starts:

The two classes are currently (September 2021) called dark_background and light_background, respectively. Never mind the name - if you want to style them differently then simply modify these classes in your web-page. Right now this is not trivial if you re-use the distributed .css files; at another moment in time the API may be changed to allow you to re-define the CSS class as-is.

Editing content on a webpage

You can make some content editable. This currently (March 2017) only works for the e() tag, which creates a span-tag.

The command for this is:

{ :editable }

To do this, try:

p {
  e('This text should now be editable.') { :editable }


All meaningful options that can be configured, can be configured via a yaml file. Settings such as the global font size and so on.

This is stored in the file cyberweb_configuration.yml.

Do simple counting via list()

Do simple counting via list().

list "one"
list "two"
list "three"

To reset it again, do:




To use a specific CSS style for these listings, do something like:

Cyberweb.listing_css = '<b class="red">'

You can also make use of ordered lists, via:

ordered_list %w( cat dog parrot deer horse )

This would yield exactly this String (if you use Cyberweb::WebObject):


You can link in other pages via the method link().

This method also accepts '*', in which case we will try to use Dir.glob (or more accurately, Dir[])

Specific Usage Example:

link 'BIOCH*/BIOCHE*.cgi'

The licence of the Cyberweb project

Since as of May 2021 the cyberweb project is using the MIT licence.

You can read the requirements for this licence here:

Before May 2021, cyberweb used the GPLv2 licence. The reason as to why the licence was changed was mostly because I consider the cyberweb project to be not extremely "important" in regards to mandating that the GPL-specific restrictions should apply. I ultimately don't quite care about the licence in regards to the cyberweb project. If others find the project useful then this is fine. If they want to contribute code, that's fine - and if they don't want to, that's fine as well, as far as the cyberweb project is concerned.


The method Cyberweb.string_image() can be used to return a proper HTML img tag, as String. This can then be used to embed it into some website.

The input to this method will be an Array, since we use *args there. The first entry should be the URL to the image at hand - this can be a local URL or a remote URL.

A Hash can also be given. Such a Hash should have a key called :url to denote the image.

Note that the method Cyberweb.string_image() is quite long, in order to cover for different use cases. The document here will not detail all these options, but a few may be explained next:

:guess_id           # This means that the ID will be "guessed" based on the filename at hand.
:guess_draggable_id # This is as above, but will prepend the string 'drag_' before, to allow for dragging the image at hand.

Personally I use :guess_draggable_id usually, as it helps me remember what this is doing. :-)

To make all images draggable, use this API:

enable_drag_all_images # Or this variant.

Drag and drop support in general and drag-and-drop support via Dragula

Via the new attribute draggable="true" it is possible to drag any element in HTML. An image can simply contain set this attribute.

The JavaScript library Dragula is used, aside from jquery, for drag-and-drop support.

If you wish to make use of it, keep the dragula-related entry set to true in the file project_configuration.yml.


use_dragula: true

Keep in mind that the ID for a HTML tag has to have a certain format. For instance, using a '.' dot is not allowed as part of an ID; this is why cyberweb will automatically replace this via a '_' character instead.

Since as of May 2023 you can also determine that all images on a given webpage can be dragged by the user (via the mouse).

First, enable this for the web-object at hand via:


Past this point whenever you call img(), it will be assumed and treated to be quite similar to dimg(), which stands short for draggable_image().

Sinatra interface

The Cyberweb project is a toolset project, so there is also a class called Cyberweb::Sinatra. This can be used to quickly write a subclass for use as a web-page, based on sinatra.

To use this in your own code, do subclass from it such as via this variant:

require 'cyberweb/requires/require_sinatra.rb'

class Foo < Cyberweb::Sinatra

@root_string will carry the content (aka the index) of the main / route by default. A few other projects make use of class Cyberweb::Sinatra, such as the studium gem or the beautiful_url gem - see files such as studium/lib/studium/www/sinatra_main_entry.rb or beautiful_url/lib/beautiful_url/www/app.rb.

Since as of June 2021 I am changing the old approach in regards to .cgi files. While I will retain support for .cgi files, I am also exploring offering the very same content via sinatra for some of the files - at the least in the roebe project, as a test-project for now. My idea here is that the Cyberweb project can already handle all HTML, CSS or JavaScript-related part that I may need. On Windows, using .cgi is somewhat annoying (but possible - I use lighttpd for this), whereas using sinatra is a lot simpler. So my idea is that I will slowly add and extend support for both .cgi and sinatra, and re-purpose the cyberweb project to achieve this. This currently lacks documentation, but eventually I'll add more documentation in how to solve this.

You can designate that Cyberweb::WebObject is serving a sinatra application right now via the following method invocation:


And to query the state:


If you use a file extension such as .sinatra then this is automatically done. In fact that was the reason why I added this functionality in June 2021. The idea in the long run is to be able to do sinatra-specific calls that enable or disable certain things, in particular in regards to images, and have images work properly at the least on my home setup.

draggable_image() and the HTML draggable attribute

HTML added the draggable global attribute. This can be either true or false. A value of true indicates that the element can be dragged.

So, for example, in HTML:

<img src="cat.png" draggable="true">

This should enable drag-support for that image.

The default value is auto, which means that drag behaviour will default to the given browser behaviour. Only text selections, images, and links can be dragged by default. For other elements, the event ondragstart must be set for drag and drop to work.


To quickly display an in-dir image, that is an image that resides within the current directory, you can try the following API:

in_dir_image 'foobar.png', 'marl3em bblack1'

Generate system settings

If you want to store the system settings in a file, you may be able to use this:

cyberweb --systemsettings

Normal users of cyberweb won't need this functionality. I only wanted to have this available as a separate instruction, to simplify updating the cyberweb project.

Textarea in HTML

You can make a textarea HTML tag readonly via readonly, as an additional attribute to the textarea-tag.

Specific example for this:

<textarea readonly>

To prevent a textarea from being resized by the user, use a CSS rule such as:

textarea {
  resize: none;

The example cyberweb/examples/html/readonly_textarea_example.html demonstrates this.

CSS first-line rule

The first-line rule can be used to style the first line in a given HTML tag (the specified selector), such as the p (paragraph).


  font-size: 30em;

The first line would then appear larger and in another colour.

Another example:

  font-size: 40px;
  line-height: 50px;
  font-weight: bold;
  color: #662929;

In some ways this is similar to using a h-tag such as h1 or h2.

Several properties can be modified within the :first-line rule, such as font properties, color properties, background properties, word-spacing, letter-spacing, text-decoration, vertical-align, text-transform, line-height or clear.

CSS text-transform properties

The three main variants are:

div.a { text-transform: uppercase; }
div.b { text-transform: lowercase; }
div.c { text-transform: capitalize; }

CSS letter-spacing property

letter-spacing can be used to decrease or increase the distance between texts within a given text.


<div style="letter-spacing: 5px"><h2>Hello world!</div>

CSS and the border-spacing property for HTML tables

You can style HTML tables via CSS, by making use of border-spacing.


border-spacing: 20pt

The values for border-spacing can be: length|initial|inherit.

IDs for use in HTML tags

An ID may occur only once on a given webpage.

CSS text-decoration

Via text-decoration you can modify text such as by underlining it or line-through the text.

Examples for this:

h1 {
  text-decoration: overline;
h2 {
  text-decoration: line-through;
h3 {
  text-decoration: underline;
h4 {
  text-decoration: underline overline;
h5 {
  text-decoration: underline overline dotted red;
h6 {
  text-decoration: underline overline wavy blue;

As you can see from the last example, you can combine several values for the same modifier, e. g. both underline and overline.

The allowed values for text-decoration are:


HTML Frames

HTML frames are rarely used nowadays. Syntax-wise they may be defined like this:

<frameset rows="100,*,60"> <frame ...></frameset>

Two frames:

<frameset cols="200,*">'),'default'
<frame src="contents_of_frame1.html">
<frame src="contents_of_frame2.html">

HTML accesskeys

You can use an accesskey in HTML like so:

<input type="button" value="Button (accesskey is b)" accesskey="b">
<button accesskey="f">Foobar</button>

The attribute accesskey is allowed in the following tags:


CSS ::before and CSS ::after

Via :before it is possible to insert elements before another element. Even graphics can be inserted.

Let's look at a simple example:

p::before {
  content: "Read this: ";

As you can see, the text that should be inserted comes after the content: part.

This can also be used to play audio files:

h1::before {
  content: url(beep.wav)

Now a slightly more convoluted example:

h2::before {
  content: "";
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: hotpink;
  displEvolution_of_Metabolic_Pathways-2000.pdfay: inline-block;
  vertical-align: middle;
  margin-right: 10px;

To make use of an image, you can use something like:

img:before {

CSS2 used the :before notation, but this was changed to :before in CSS3. I was a bit surprised to see ::before, because I used to use :before only.

The same exists for appending text, called ::after.


p::after {
  content: "»";
  color: red;

CSS input autofocus

You can modify elements by setting the focus onto them the moment a page loads, via autofocus.

Example for this:

<form action="/action_page.php">
  <label for="fname">First name:</label>
  <input type="text" id="fname" name="fname" autofocus><br>
  <label for="lname">Last name:</label>
  <input type="text" id="lname" name="lname"><br><br>
  <input type="submit">

This is a bit similar to ruby-gtk3, e. g. .do_focus or .set_focus(true).

CSS grouping and CSS selectors

CSS selectors, such as the typeselector, can be used to refer to specific HTML tags. This can be used to style these HTML tags via CSS rules.

The following example shows how to use a margin of 10 pixels for each p tag:

p { margin: 10 px; }

This is fairly convenient and elegant. It is also quite flexible in that you can group several selectors together, and apply the same CSS rules to each element listed therein.

You have to use a ',' as separator between the individual elements in order for this to work.

An example for this follows:

h1,h2,h3,h4,h5,h6 { color: green; }

Now all HTML headers (h1 up to h6) will be displayed in a green colour.

This can be extended for particular tags that occur as part of other tags as well.

For example, in order to colourize all h2 headers that occur within the ID called #nav, use the following:

#nav h2 {
  color: tomato;

In plain HTML this would be used via code like this:

<div id="nav">
  <h2>Hello world!</h2>

This allows you to use conditional rules in CSS. Don't forget to use the correct ID; in this case #nav.

CSS box-shadow effects

How does box-shadow work in CSS?

The general syntax may look like this:

div {
  box-shadow: 10px 10px 5px #888888;
  h3 'Hier die obige Box'

See also:

The allowed values to box-shadow are:

box-shadow: none|h-shadow v-shadow blur spread color |inset|initial|inherit;

h-shadow refers to a horizontal shadow, whereas v-shadow refers to a vertical shadow.

A box-shadow Generator can be used as shown on the following webpage:

Add a .js file, as-is

The following API can be used to ad-hoc add a .js javascript file:

link_in_javascript 'app.js'

CSS Cursors

To use a different cursor, set a CSS style rule such as:

cursor: pointer;
cursor: auto;

Alternatively use a defined CSS class such as:

.crosshair { cursor: crosshair; }

And then in HTML:

<p class="crosshair">crosshair</p>

Valid cursors include:


Using language-specific files as content of a webpage

The typical way how I describe the main content of a web-page is via:

doc {

This doc refers to document and is ultimately just a <div> tag. So I put my web-applications into a big <div> tag ultimately.

Since as of late 2020 I am also using language variants such as:

english {

# or

german {

The latter is used for denoting that this webpage is written in german, and the former is used when the webpage is written in english. This is not a replacement for doc {}, but is the starting point I use for describe a web-object in general.

In June 2021 this was extended in that I added the method called:


The word skeleton refers to a separate file, the skeleton of the web-application.

Say that you have five files called index.rb, index.cgi, index.sinatra, and

This allows us to read in either the english or the german language, as-is.

To let the cyberweb project guess on its own, consider using a variant via the following Symbol:


This currently defaults to german. You can pass ?use_english or ?english to the .cgi page to overrule this and force the web-application to view the english content instead. That way the user can change languages, as-is. A bit cumbersome for now, but possible.

In order for this to work, the corresponding .md file must exist, e. g. or

Note that this is currently (June 2021) quite experimental, but I wanted to add the feature that we can offer different languages. In the long run I may adapt this approach, to make it easier to use different languages on any given web-application, but for now I only use this in the roebe gem. For example, luft.cfg under roebe/www/luft/ will show this. It may not work on your home system, though, as it is catered to my home setup currently. But it shows how this could be done in theory. So, who knows - in the long run I may integrate this as a 'default' feature.

Note that ?use_german will work as well, to force the file to be read.

CSS border-style property

CSS gives you the possibility to style borders via different properties, through border-style.

Let's showcase some examples for this:

p.solid  { border-style: solid;}
p.dotted { border-style: dotted;}
p.dashed { border-style: dashed;}
p.double { border-style: double;}
p.groove { border-style: groove;}
p.ridge  { border-style: ridge;}
p.inset  { border-style: inset;}
p.outset { border-style: outset;}
p.none   { border-style: none;}
p.hidden { border-style: hidden;}
p.mix    { border-style: dotted dashed solid double;}

Personally I like solid the most, followed by dotted, then dashed.

The other properties may be useful in some cases, e. g. when you wish to indicate some button-like element - but visually, I think the first three styles are by far the most appealing ones.

Styling a row of a table and styling a table in general

You can use CSS rules such as this:

tr {
  background: wheat;
tr.even {
  background: none;

This can be used to use a different colour for each even row. You still have to use the CSS class called even in this case manually, though. (There may be other solutions but for now this is simply documented here as-is - perhaps in the future this may become more flexible.)

This may look like this:

See also the file at cyberweb/examples/html/table_with_header_example.html.

CSS first-letter

CSS allows us to modify the first-letter in, for example, a HTML paragraph. This is enabled via the so-called :first-letter selector.

In CSS rule this will look like this:

.fl:first-letter { font-size: 120%; }

The ':' is the important identifier.

Some time ago this was modified though. It is now required to use two ':' rather than one.


p::first-letter {
  font-size: 150%;
  color: steelblue;

Take note that this is limited to block-level elements, so by default the span tag is unable to make use of this, unless it is turned into a block-level element as well.

CSS and Hovering

CSS allows us to make use of :hover in order to have certain effects happen when the mouse cursor hovers over an element.

The general API respectively syntax for CSS hover goes like this:

.NAME_OF_ELEMENT:hover { background: COLOUR_HERE; }

.NAME_OF_ELEMENT:hover { background: COLOUR_HERE; }
.test:hover { background: green; }
.button:hover {opacity: 1;}

To then test this via cyberweb:

p('hover_test2 mart1px','') {
  ee sg(:pfeil_rechts,'marl1em marr6px')+
     'Hier drüberfahren'

To make all HTML links, aka the a tag, change the colour when the mouse hovers over them, the following CSS rule should work just fine:

a:hover {
  background-color: yellow;

You can style several tags in one go, via:

p:hover, h1:hover, a:hover {
  background-color: lightblue;

This also works inline.

The CSS !important rule

Let's start with a syntax example.

Consider the following CSS rule for the body tag:

body {
  background: steelblue !important;

This will set the background colour of the whole body of the page to the colour steelblue.

It is important to use that very syntax, e. g. to close the CSS rule at hand via !important;. Otherwise it may not work properly.

Once such an !important rule applies then it takes precedence over every other rule, including the style attribute. Later set !important rules can override earlier set !important rules, though.

Use this with caution, though, as it really overrides any other settings, including user-defined settings.

Including external .css files

The syntax for adding external (standalone) .css files is as shown in the following examples:

<link rel="stylesheet" type="text/css" href="name_of_the_css_file_goes_in_here.css">
<link rel="stylesheet" type="text/css" href="base.css">

Embeddable Interfaces

Since as of June 2021 I am experimenting with embeddable interfaces in regards to web-related components - most importantly sinatra.

The basic idea here is that we can easily make available additional routes for other applications. Let's explain this by using an example.

The PdfParadise project defines a route such as /view. This entry will become /pdf/view if I want to use it within the Roebe::Controller - my master-class for controlling all the various web-APIs that I use locally.

To enable this functionality, I decided to settle for a module name called EmbeddableInterface. I am trying to use this consistently for my own projects. Different details may change, but ultimately this should be used when I want to extend functionality of the core controller.

This module then typically looks like this:

module EmbeddableInterface # === Wetter::EmbeddableInterface

    require 'html_tags'
    include HtmlTags::BaseModule
  rescue LoadError; end

    require 'cyberweb/sinatra/custom_extensions.rb'
    include Cyberweb::Sinatra::CustomExtensions
  rescue LoadError; end

  # Some methods defined next

def self.embeddable_interface
  object =
  return object

That's the skeleton for it right now, roughly.

In the future this may be simplified, but for now this is the way it is.

You can use the following toplevel method for merging new routes into an application; again, for the time being, this is a bit hackish. It may take a while before this becomes officially endorsed.

The API is:


Arguments should be:

  i, # Should be an Array of routes that are to be used.
  prepend_this_to_the_route = '/',
  namespace_to_use # For example, PdfParadise or Repackage.

Some methods are assumed to exist within module EmbeddableInterface. This may be subject to change in the future, but for now simply look at the repackage gem to find out how this is done. Documentation is missing in this regard, but will be added over the next weeks slowly.

Including CSS into a webpage

If you want to include CSS into a webpage, use the following HTML tag:

<style type="text/css"></style>

Including external .js files into a HTML (web)page

The syntax for adding standalone .js files goes like this:

<script type="text/javascript" src="path/to/javascript/file.js"></script>

# or simpler:

<script src="path/to/javascript/file.js"></script>

CSS comments

If you want to use comments in a CSS file, use something like this:

/* This is a CSS comment. */

CSS font-face property (in CSS3)

Via the @font-face property it is possible to make use of different (custom) fonts. This font can be loaded from a remote server, or it can be provided on the local system, thus a locally installed font on the user's computer.

An URL should be given as argument.

The syntax rules for this goes as follows:

(1) first give the name of the font
(2) provide the path to the font

If you then wish to make use of that font you can declare this in CSS.

An example for this follows:

@font-face {
  font-family: myFirstFont;
  src: url("sansation_light.woff"); # Here you can provide the URL

Another example:

@font-face {
  font-family: "Open Sans";
  src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2"),
       url("/fonts/OpenSans-Regular-webfont.woff") format("woff");

Lazy loading of images

You can use loading=lazy to defer the loading of that image until the user scrolls to the image.

Example in HTML:

<img src='foobar.jpg' loading='lazy' alt='Alternative Text'>

CSS zoom-on-hover effect

This can be done like this:

.images {
  display: flex;
  width: 100vw;
  juftify-content: center;
  align-items: center;

img {
  width: 400px;

img:hover {
  transform: scale(1.3);

/* And another example:
img:hover {
  transform: scale(2.5);

The important part is the transform: scale specification. You can here specify how large or small the image should become. For instance, to shrink an image, you could use the CSS rule transform: scale(0.5);. This will shrink the image to half its original size.

I typically put these rules into a special CSS class, such as:

.enlarge_this_image_on_hover:hover {
  transform: scale(1.1); /* Just a modest increase. */

And then, for instance, for a generate image tag:

img(:document, 'enlarge_this_image_on_hover')
# or this example for a draggable image:
dimg 'BOX.png', 'VAM enlarge_this_image_on_hover'

The small drawback (or advantage, depending on your point of view) is that the CSS rule has to be specified as-is.

In theory we could also autogenerate the CSS rule and use an API such as img(:document) enlarge_this_image_on_hover: '25%' } instead, but for now I'll leave it with the above CSS-based approach. It's quite simple really.

Valid values for CSS font-size:




Cyberweb::Header.size = 'h3' # Set to a smaller header.

Not sure if this is still necessary in 2021; at a later time it will be decided whether to keep this or not. If it is kept then this subsection will be expanded.

Working with HTML form elements

Within a HTML form tag, the following tags are valid or have a special meaning:


CSS ::before rule

You can add content via CSS like this:

.some_class::before {
  content: "Only today offer ";
  font-size: larger; 
  color: red; 

<p class="some_class">Wood only € 4.95</p>

I don't think this is too overly useful when you can dynamically generate the web-app as-is, though.

How to work with form-elements

This subsection was added because I tend to forget how to work with <form> elements in HTML.

HTML allows us to make use of <form> elements.

Any such <form> element is typically associated with an action, which is determined via action="".

This may look like this:

<form action="/foobar.php">

The attribute action determines the recipient, that is, the one who will receive the transmitted data from the <form> element. In the example above, the file called foobar.php.

The attribute method determines how the data will be transmitted. If omitted then the default is get.

You can also send this to an email, such as via this:

<form action="" method="post" enctype="text/plain">

Within any such given element, we can use <input>, as in:

&lt;input type="text" id="first_name" name="first_name"> 

To use a web-form via cyberweb, try:

form('SELF', :post, 'mars2em') {


Since as of 24 Aug 2011 we can also use the method simple_table2() which is stored in the file html_tables.rb.

Example for this:


This will simple make a 2 data-cell table, and accepts an Array as its input. Very easy way to make tables!


A sitemap is a navigational tool, displaying to the user which links may exist on a given webpage.

If you want to use a sitemap via the Cyberweb project, do something like this here:

sitemap :h4, 'Schnelles Abnehmen'

If you also want to autogenerate a sitemap, as-is, then you can use the following method:

header_for_sitemap 'This is some generic header.'

You can also use an Array for a special method:


This will be treated as an Array of headers to be used for the sitemap that will be generated.

Generating standalone webpages (.html files)

This subsection deals with the cyberweb project generating standalone .html files.

First, the general method to create a HTML dump is via:


This is only possible on a WebObject instance. This alone will just return the HTML representation.

To store it into a local file use this method:


This presently (August 2021) uses hardcoded file paths. In the future more flexibility will be added to the method, but for the time being it was only added to quickly do some ad-hoc testing.

Spinbuttons in HTML

Use something like:

<input type="number" value="1" min="1" max="999">

You may even style them via CSS like:

input[type=number]::-webkit-inner-spin-button {
  opacity: 0.3

Since as of 19.02.2020 (19th February 2020), the cyberweb project now uses the HtmlTags project for generating a href hyperlinks (HTML hyperlinks).

While this led to some broken links on my home system, the code as well as the usage pattern for links is now more consistent, and simpler to use in the long run - I hope. Before that I used tons of different HTML-generating methods, all of which used different signatures. This was too confusing to maintain in the long run.

The typical API for use of such a HTML link may look like this:

a 'ät_xyz.html',
   content: 'Handbuch zum Gerät xyz',
   css_class: 'mars2em'

So essentially, you can describe the HyperLink as a Hash, where content is the content (the text you wish to display), css_class is the CSS class to use for that link, and so on and so forth.

For the actual CSS code, I recommend to group the a-related tags together, such as via:

a:link, a:visited, a:active { color: #3366FF; text-decoration: none; }

The hover-action should be styled separately:

a:hover { color: #006699; text-decoration: underline; }

To globally style all HTML hyperlinks, you can use CSS style such as the following:

a {
  color: steelblue;

Remember that you can also use a title for a href tag. Example:

<a href="" class="slateblue" title="Some Superlong Title here">

The br-tag

The br-tag can be used in HTML to add a linebreak.

You can style the height of the line break via CSS such as:

br {
  line-height: 30%;

I needed this on a webpage to control the distance between individual HREF-links, and I did not want to use div-tags or p-tags as such. So using the line-height property was very useful.

Remote images versus local images

I use various www-related projects, including local webpages.

Some of these pages lateron became available for everyone, such as in the roebe gem, via the www/ subdirectory.

However had, images are normally not distributed for these webpages - it would inflate the gem size way too much.

This in turn means that a visitor does not see any image, when some of these images are important or helpful. This is not an ideal situation.

So, in September 2021 I decided to add a new API, called:


The idea here is to default to my local image, but to provide a second argument as well, containing a remote URL to an image that can be used as a substitute, in the event that there is no local image available (such as when other users look at a webpage distributed in the roebe gem).

I tested this in September 2021 and it works, so in the future I expect a few more images to be made available. But this is quite experimental as of now, and probably still not too hugely useful for other users. In the event you may have a need case to document such a web-page via images, you can modify these API calls and supply your own images.

If you do not need drag-and-drop support then simply use:


If drag_local_image_or_remote_image() is too long to type, use the alias called dimg2.

To quickly embed a remote image, you can use the following API:

embed_remote_image ''
embed_remote_image '','mar1em mars2em' # This here passes CSS classes to the image at hand.


This method can be used to 'convert back' german umlauts, when the encoding failed somewhere, such as converting '%d6' into 'Ö'. It is mostly an ad-hoc method that most users of the project will not need, but sometimes there may be a use case to make use of that method, such as when one uses open-uri to download a remote website into a local file, if said remote website contains german umlauts.

In fact this was precisely the reason why that method was added.


The file cyberweb/yaml/autogenerated_system_settings.yml is created via the external file roebe/classes/generate_system_values.rb.

This file will contain entries such as:

SYSLIB_DIR: "/usr/lib/"

This was needed because in some environments these directories are not defined, yet there are examples where the cyberweb project may need to know these paths. Thus, the hardcoded values are stored in that .yml file. You will probably never need the .rb file or the .yml file, but it is here documented to explain why it exists.

Column width in CSS

You can specify a column width via column-width: 250px;.

The following screenshot shows this:

The meter tag in HTML

HTML allows us to use a meter tag.

Example in HTML:

<label for="value1">Low</label>
<meter id="value1" min="0" max="100" low="30" high="75" optimum="80" value="25"></meter>

This would eventually yield a page that may look like this:

This is documented here in the event that we may need this one day.

Unicode and Encoding

This subsection is currently a stub - in the future it may be expanded to contain more useful information.

On the world wide web you can sometimes see greek symbols displayed on a homepage. This often makes use of the "math> tag.

Preliminary support for this was added to the cyberweb project in October 2021. This is incomplete right now but hopefully will become more inclusive in the future.

Following next is just one example to add (display) the greek symbol omega on the webpage at hand:


Sanitizing .html files

Sometimes a .html file is "compressed", aka newlines are removed. Everything is then on a single line.

Some editors struggle with this; and it is quite ugly.

Thus, an ad-hoc method was added to Cyberweb.

Its API is:


Pass a local .html file to the method; alternatively a String should do well. Every closing > html tag found will be turned into ">\n" instead. Thus, you get a nicely split .html page. (Ideally we should use a more sophisticated regex, but I really added this just as a throw-away action, to sanitize a mangled .html page.)

This can also be called de-minify-script.

Placeholder text

Placeholder text can be assigned to a textarea HTML tag. Let's first show the raw HTML code for this, mixed in with a bit of CSS:

Describe the physical attributes of your character next:<br><br>
<textarea rows="4" cols="50" style="margin: 1em" placeholder="Describe your character here ..."></textarea>

This would yield the following result in the browser:

You can use the input tag to designate a placeholder text to use.

Only two HTML attributes can receive the placeholder attribute. These are:


An example for this follows for the input tag:

<input type="tel" id="phone" name="phone" placeholder="123-45-678" pattern="[0-9]{3}-[0-9]{2}-[0-9]{3}"><br><br>

And for the textarea tag as well:

<textarea placeholder="Describe your complaint here ..."></textarea> 

See also the distributed example file at *cyberweb/examples/input_placeholder_example.html.

It is possible to style the placerholder-text via CSS.

For instance, if you would like to use the color *steelblue then use the following CSS rule:

::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
  color: red;
  opacity: 1; /* Firefox */

CSS rules in general

This subsection contains a few explanations to CSS rules in general.

Inheritance: after a property has been applied to a particular element, its children retain those property values as well. That way you can consistently style these elements via the same CSS rules.

Normally when a CSS value is changed, the change is instant. This can be avoided by the transition property, which allows us to animate from the old state to a new state.

Working with base64-encoded data (image)

Have a look at the following file:


The idea is that we can eventually embed all images as base64 encoded variants. This is especially useful for sinatra and rack-based applications. Right now this is fairly experimental; in the future it will become easier to use.

Remote images at imgur

I have some local .cgi files that request images stored in a path that is not accessible by the local webserver. Sometimes I can put it into WebImages and use it, such as via Base64 encoding - but sometimes I just want to be able to link to it via an img tag. So in these cases I am fine linking in to remote images.

As I may forget which image is available, here comes a listing - this may be extended over time:

Downloading a remote webpage

You can use Cyberweb.download_webpage() to download a remote webpage.

This isn't hugely sophisticated - it just performs and then dumps that string into a local file. The file bin/download_webpage is representing that functionality from the commandline.

Usage example from within Ruby code:


Tooltip example via CSS

A tooltip is often used to specify extra information about something when the user moves the mouse pointer over an element.

Have a look at the file at cyberweb/examples/css/css_tooltip.html.

This shows a simple CSS tooltip. Adjust the style, colours, width according to your own preferences.


You can use the method call hr_stars to display three stars aligned one to another.

This may look as the following image shows:


This module shall eventually replace sinatra for my own needs. I will not port all of sinatra's functionality, but I want to be able to use the core functionality for my own custom web-related needs.

To use puma, use:


And for webrick, use:


These methods were added mostly for convenience. If you are curious have a look at the code to find out which is the 'real' method.

Rebuilding Sinatra

Sinatra is a small webframework, built on top of Rack. It provides a useful DSL for specifying what the given application should respond to, and what it will send back.

The DSL can be as simple as shown in the following example:

get "/hello" do
  [200, {}, "Hello from Sinatra!"]

post "/hello" do
  [200, {}, "Hello from a post-Sinatra world!"]

The get() method must take a path (which is the first argument) and an associated handler block - which is the part within the do/end clause.

A very simple definition may be the following variant:

def get(path, &handler)
  route("GET", path, &handler)

def route(verb, path, &handler)
  @routes[verb] ||= {}
  @routes[verb][path] = handler

So, in other words: we will append new verb-entries to the main hash called @routes.

This can then be used like this:

route_handler.get "/hello" do
  [200, {}, ["Hello world!"]]

puts route_handler.routes

The next method that has to be defined, if we want to support Rack, is .call(), such as:

def call(env)


Since as of November 2021 the cyberweb project makes use of Hover.css (licence: MIT):

The .css is distributed as-is. Note that some names were changed, though, to make it more 'logical'.

Web-safe fonts

The following list is assumed to contain web-safe fonts, for use in HTML pages (via CSS):

Arial (sans-serif)
Verdana (sans-serif)
Helvetica (sans-serif)
Tahoma (sans-serif)
Trebuchet MS (sans-serif)
Times New Roman (serif)
Georgia (serif)
Garamond (serif)
Courier New (monospace)
Brush Script MT (cursive)

Note that the names of CSS fonts in general are case insensitive. Thus you can lowercase them too, if you would like to.

You can also use generic fonts. Five are available by default, being: serif, sans-serif, cursive, fantasy and monospace. Serif resembles Times New Roman, sans-serif resembles Arial.

Most text on the Web is displayed with a sans-serif font family.


You can download the balloon.css file via class DownloadBalloonCss (Cyberweb::DownloadBalloonCss).

This file resides at the location web_object/utility_scripts/download_balloon_css.rb.

It presently (May 2018) does not do much other than download that remote .css file.

I needed a small "pop-up" for displaying additional information to some entries in a table, which is how I found Balloon.css.

Grayscale filtering on an image

CSS allows us to "remove" colours in an image. I call this the grayscale filter.

Cyberweb comes with a default CSS class that may be of help here - simply attach the CSS class grayscale to the image at hand if you want it to "lose" colours (for display purposes only; of course nothing is lost in the image as such, only the display of said image is modified via CSS).

Converting from a .html page to a cyberweb-object

The file bin/html_to_cyberweb_converter can be used to convert some .html files into cyberweb-objects. This class has been created in February 2022, but it does not yet work very well. In the future this may change.

The idea is that we can grab any .html page, re-build its logic into cyberweb, and allow you to modify this in any way, shape or form. The long-term goal is to adjust any .html page to any different format, in any way, shape or form. It would allow users a higher level of abstraction to deal with a HTML page. For instance, you can re-style the CSS classes in use as-is.

(Note that presently, as of 2022, class WebObject is actually not used; HtmlTemplate is used instead. The reason is because WebObject is too big and not flexible enough right now. In the future this may be resolved and unified, but for now, class HtmlTemplate will generate the new .html file.)


If you make use of Cyberweb::WebObject then you may be able to describe a webpage as an "object". Various methods will be made available at that point.

The API may include a sort of DSL like this:

english('Title goes here') {

This kind of means that the webpage at hand will be using english as its primary language. And the first argument will become the title of that webpage. (Note that presently only english() and german() are available. It's not making any real difference, but perhaps I should add alias-names for other languages as well. Not so many users of this project aside from english as the primary language in use, though.)

Various other methods part of WebObject exist that help here, one of which is autoextend. This method is also aliased onto enable_namespace.

That method will include various other modules. One module that was somewhat recently (March 2022) added was Cyberweb::Objectified::Mask. This module will pull in HTML-tag support. So, for instance, oop_h1() can then be used as a method, which will refer to using h1 as the HTML tag. These objectified (OOP) HTML tags are described in more detail in other subsections of this document (

Including the namespace for Cyberweb::Objectified::Mask is done mostly for convenience, so that the user does not have to manually include this module.


The Cyberweb framework/toolset favours the use of jquery. Presently, since May 2021, the version that is to be used by default will be for jquery 3.6.0. This may change at a later time.

In the event that it is changed and the documentation here is not updated, you can always rely on the following method call to yield the correct version of jquery to be used:


For example, the above method called would yield 3.6.0 in May 2021. Personally I always use the latest stable version of jquery when possible.

You can also query the jquery-ui version in use, via:


Again, this also has to be synced manually, via the .yml file called project_configuration.yml.

Since as of May 2021, the cyberweb will also bundle this corresponding version of jquery and jquery-ui into the javascript_code/jquery/ subdirectory of the gem. This is solely done to simplify the use of jquery so that, for example, dragging an object becomes simpler and available by default, even if access to the www is unavailable at the current time.

You can also call this method on a Cyberweb::WebObject instance via the following method:


Both jquery-ui and jquery use the same licence as the Cyberweb project (MIT licence). See also this wikipedia entry if you want to read more about jquery and its history:

To make a container resizable via the mouse, by using jquery, try this method:

jquery_resizable_via_the_mouse(id: :resizable_via_the_mouse)

As id you simply pass in the id of the HTML element at hand. In this case, the symbol called :resizable_via_the_mouse.

See also the file for a more thorough reference.

Note that in May 2021, support for jquery is actually mildly deprecated. This is not set in stone and it does not mean that jquery support will be removed, as far as the cyberweb project is concerned; it is more that I want to see whether we have better or simpler alternatives, without being tied into jquery too closely.

The basic syntax for jquery, in javascript, goes like this:


The general rules for JQuery go along these lines, in JavaScript:

$(this).hide()    # hides the current element.
$("p").hide()     # hides all <p> elements.
$(".test").hide() # hides all elements with class="test".
$("#test").hide() # hides the element with id="test".

Some of this is a bit cumbersome to type and use, so the Cyberweb project simplifies some of it.

For instance, rather than type out the document_ready functionality via $(document).ready(function(){} you can simplify this via the following method:

document_ready() # No arguments in this case, which is rather pointless.
document_ready('$("h1").css("color", "lightgreen");') # ← Real usage example here.

This may not appear to be of a huge help, but it gets rid of a bit of boilerplate code, which I think is useful in its own right. Future changes may even simplify this further, but for now let's keep it simple.

Jquery mini-tutorial

This subsection will contain some useful snippets pertaining to jquery. It will be a mini-tutorial, NOT a complete tutorial.

To select all

elements via jquery, use:

$("*") # will select all elements

To select all specific CSS classes, use:

$(".info") # to select the class called .info
$(".info,.features") # to select all elements with the class info or features

To select the ID, do:


You can also select based on href-attributes, via:


Via $(document).ready() jQuery defers the function calls until the DOM is loaded.

To add a CSS class to every p-element, you could use this jquery-code:

$(document).ready(function() {

      $('p').addClass('highlight'); })

Here, the name of the CSS class would be highlight.

The CSS class called select_everything

This document already mentioned how to use JavaScript to select everything.

Interestingly it is possible to achieve the same nowadays, without JavaScript - by making use of CSS*.

Cyberweb integrates this via the CSS class called .select_everything.

Simply add it to any tag and when the user clicks on it via his or her mouse, then all content is selected. On Linux this will also assign to the xorg-buffer, so you can use a one-left mouse-button click, and then use the middle-mouse button to paste it onto the commandline. Very convenient! \o/

CSS tables versus original HTML tables versus flexbox and grid layouts

There are various possibilities to lay out HTML containers on a webpage. The simplest one is the old HTML table. This one worked really well.

Lateron we had support via simple div-tags, as well as the float element. Then came grid layouts and flexbox.

Which variant to use?

Well - I have consistently had problems with both grid layouts as well as flexbox. HTML tables, on the other hand, work really well, and so do CSS tables. I have no idea why, but for me CSS tables seem to be the best variant. Flexbox and grid lead to increased complexity, and always created issues for me, so I mildly deprecated using it instead; perhaps one day they will become simpler, but for now I will stick to CSS tables.

How to use a CSS table? Make use of display: table; as well as display: table-row. That way you can kind of simulate tables.

The following CSS rules show this:

.grid {
  display: table;
  border-spacing: 5px
.row {
  display: table-row
.cell {
  width: 50px;
  height: 50px;
  background: grey;
  display: table-cell;
.row div:last-child {
  background: red

If you need to set a maximum width then the following may work:

<table style="width: 90%; table-layout: fixed">

Working with local files in HTML - input type="file"

You can use:

<input type="file">

To give the user a way to handle local files conveniently.

You can limit the file types handled by this input tag via:

accept="image/png, image/jpeg"
<input type="file" accept="image/png, image/jpeg">

CSS, text-shadow support and drop-shadow support

The CSS text-shadow can be used to simulate an engraved text.

If you want to have shadows added to a given text then the text-shadow CSS property may be useful. Be careful when using this, though, because it can make the text harder to read - so perhaps use it only for some headers or larger text rather than for all text content.

At any rate, let us next look at a simple example for the h1 HTML tag, how it can be styled via the text-shadow CSS rule:

h1 {
  text-shadow: 2px 2px #FF0000;

The syntax used here (and in general) is as follows:

text-shadow: h-shadow, v-shadow, blur-radius, color
text-shadow: 1px 1px 2px black;
text-shadow: 2px 5px tomato; /* Note that you can also omit values, as seen here on this line. */

Another example, for a CSS rule:

.red_text_shadow {
  text-shadow: red 0 -2px;

Strangely enough you can also re-arrange the arguments a litte bit:

/* colour | offset-x | offset-y | blur-radius */
text-shadow: #fc0 1px 0 10px;

/* offset-x | offset-y | blur-radius | colour */
text-shadow: 1px 1px 2px black; # This is my preferred style.

I do not know why they went that route, but I recommend to just stick to one style, and avoid the other. Seems easier to remember when one can be consistent about the arguments.

Note that text-shadow is not the only way you can use to modify text. drop-shadow is another CSS property that can be used in this regard.

In CSS the rule for drop-shadow would be as follows:

drop-shadow(2px 4px 8px #585858);

More specifically what these four values mean:

drop-shadow(offset-x offset-y blur-radius color)

If you make use of the cyberweb project then you can use the following API, to generate a drop shadow:

generate_drop_shadow :red, :default, 'drop_shadow_red'
div('drop_shadow_red') {
  h3 'This part should show a drop-shadow effect - but in red'

This would yield the following text (shown as image, for convenience):

Let's look at another example:

generate_drop_shadow :darkblue,
                     '4px 2px 4px',
div('drop_shadow_darkblue pad0px mar0px') {
  h2 dot(105, 'marr12px')+
     'Fancy Text',
     'ud mart5px'

This would yield the following text (shown as image):

And let's show another example:

generate_drop_shadow :deepskyblue,
                   '6px 4px 8px',
div('drop_shadow_deepskyblue pad0px mar0px') {
  h2 dot(105, 'marr12px')+
     'Cats are adorable creatures.',

This time no image, but you get the idea - if you want a fancy border, cyberweb may help automatically generate these.

You can also use the internal CSS class called shadow_div_without_restrictions.

Give it a try on a div-element, such as via:

div('shadow_div_without_restrictions') {
  h2 'Hello world!'

See also the file at cyberweb/examples/css/shadow_example_in_CSS/shadow_example_in_CSS.cgi.

A similar effect is shown by the following image:

The important thing to look at is the border-area around the central div-container. You can see that it is surrounded via a border; that is what the CSS class shadow_div1 is achieving.

Since as of November 2021 you can also use objectified-html-tags. The drawback is that it is currently a bit verbose.


_ = Cyberweb.oop_h1('Batterien', 'martb1px')
css_manager =
css_manager.css_rule_for_drop_shadow(:lightgreen) # Generate the CSS rule here.
_.css_class 'martb1px drop_shadow_lightgreen' # Use the CSS rule - note the last part.
_.css_manager 'css_rule_for_drop_shadow(:lightgreen)'
_.add_to_pre_content css_manager.result_as_CSS_style?

Or simpler:

_ = Cyberweb.oop_h1('Batterien', 'martb1px')
_.css_class 'martb1px drop_shadow_lightgreen'
_.css_manager 'css_rule_for_drop_shadow(:lightgreen)'
  Cyberweb.css_manager { css_rule_for_drop_shadow(:lightgreen) }.css_style?

Unfortunately the second example (aka the one right above ^^^) does not work yet. I am not entirely certain how to enable this - ruby's meta-patterns begin to confuse me.

Since my brain is too feeble, I actually wrote a class instead that will autogenerate some CSS rules that can be used.

These CSS rules are stored in the file called drop_shadow.css and work without needing any meta-pattern or autogenerator.

To use these in your own scripts, do something like this:

p('drop_shadow_chartreuse')     { ee 'Hello world!' }
p('drop_shadow_chocolate')      { ee 'Hello world!' }
p('drop_shadow_coral')          { ee 'Hello world!' }
p('drop_shadow_cornflowerblue') { ee 'Hello world!' }
p('drop_shadow_cornsilk')       { ee 'Hello world!' }
p('drop_shadow_cyan')           { ee 'Hello world!' }
p('drop_shadow_darkblue')       { ee 'Hello world!' }
p('drop_shadow_darkcyan')       { ee 'Hello world!' }
p('drop_shadow_darkgoldenrod')  { ee 'Hello world!' }

This is currently hardcoded to 5px. At some point this default may change, but for now I think 5px is a good compromise.

The actual CSS rule will look like this:

.drop_shadow_cornflowerblue { filter: drop-shadow(5px 5px 5px cornflowerblue); }

This is possible for all registered HTML colours.

Have a look at the file cyberweb/examples/advanced/advanced/drop_shadow_examples.cgi to see how this may look like.

The following image shows this (partially):


Each HTML tag may have an id entry. The id entry, in HTML, is typically defined like this:

id="some_value" # A generic example.
&lt;div id="some_div">&lt;h2>Hello world!&lt;/h2>&lt;/div> # A better example.

Which values are permissive here?

For HTML4 ID tokens must begin with a letter (which is [A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".").

In August 2022 I confirmed this, via the following ID:


So you can even use '.' characters. I note this down here as I tend to forget things - so this documentation here is a reference for me as well as for others.

As far as the cyberweb project is concerned, all HTML ids are registered into an array (if you use Cyberweb::WebObject). To then show whether you have duplicated IDs in a page, do use the following method:


Or in a more general way, use the #debug method, like so:


This will report whether you have a duplicated ID or not.

When the page is served, we will also display a little error message in case we have found duplicated IDs. This way we can notify the developer that there is some mistake in his page and we can correct this mistake then.

Have a look at the corresponding source code to see how this is actually implemented.


The method .show_this_local_directory() can be used to show content of a local directory. It is available for class Cyberweb::WebObject.

I plan to extend this in the coming weeks and months. The key idea is that we can use this in .cgi scripts and sinatra to show the content of different directories.

The tag

You can highlight text in HTML via:


Showing the line numbers of the displayed content

You can show the line numbers via a trailing ?show_lines.

This is experimental as of May 2023 - it does not work extremely well. Nonetheless, the option is available.

Lazy loading of HTML elements, such as the img tag

You can use:


To load images at a later time - that is when the user scrolls to such an image, hence the term "lazy loading" for this functionality.

Let's have a look how this looks in raw HTML:

<img src="foobar.jpg" loading="lazy" alt="Alternative Text">           

So all you have to do is add the part loading="lazy" to the image tag (img) at hand.

The Cyberweb project supports this in both the traditional way, as well as the OOP variant offered by cyberweb.

The examples for this are:

img 'foobar.jpg', loading: lazy
img('foobar.jpg') { :lazy }

If you want to use it via the OOP variant:

_ = oop_image('foobar.jpg')
_.lazy_loading # or _.lazy
puts _ # => <img src="foobar.jpg" loading="lazy">

As you can see, the OOP variant of cyberweb allows us to assemble the desired HTML tag as-is. It may seem quite verbose, but remember that you also get a lot of flexibility that way.

The method images_css() in class Cyberweb::WebObject

Sometimes you may have several images and may want to apply the same CSS rules to all of them.

For instance, I use the CSS class bblack1 which is equivalent to:

border: 1px solid black;

So, if I want to apply the bblack1 CSS rule to all images in a WebObject, I do this:

images_css 'bblack1'

Past that point all images on that particular web-object will have a 1px black border.

See the example file at cyberweb/examples/advanced/images/global_css_rules_for_the_images.cgi for a demo in this regard. (Not all images work; some of them are only available on my home system, but the other images should work.)

Do note that since as of November 2022, when images_css is used then it will always be appended to every image tag. So only use it if you really need this functionality.

If a file called exists in the current working directory then a .cgi or sinatra application powered by cyberweb will read in the content of this file. Then it will display each entry in that file as a HTML hyperlink. I needed this functionality so that I can dynamically modify links displayed on a webpage, for another user of the cyberweb gem. So this functionality may not be hugely important for most users, but in case you need it, it is available.

module Cyberweb::JqueryModule

module Cyberweb::JqueryModule is used to enable or disable support for jquery. Not all classes in the cyberweb gem make use of this module right now - notably class Cyberweb::WebObject does not use this module as of yet. This is planned at some later time in the future, as some code has to be re-written, in order to make use of this new module.

The only class that uses module Cyberweb::JqueryModule right now is class Cyberweb::HtmlTemplate.

CSS Borders

CSS supports different borders.

You can control various different aspects here, such as the width of the border, or the style of the border.

The available border-style properties are as follows:

dotted - Defines a dotted border.
dashed - Defines a dashed border.
solid  - Defines a solid border.
double - Defines a double border.
groove - Defines a 3D grooved border. This effect depends on the border-color value.
ridge  - Defines a 3D ridged border. This effect depends on the border-color value.
inset  - Defines a 3D inset border. This effect depends on the border-color value.
outset - Defines a 3D outset border. This effect depends on the border-color value.
none   - Defines no border.
hidden - Defines a hidden border.

The following paragraph shows how you can use this:

p.dotted {border-style: dotted;}
p.dashed {border-style: dashed;}
p.solid  {border-style: solid; }
p.double {border-style: double;}
p.groove {border-style: groove;}
p.ridge  {border-style: ridge; }
p.inset  {border-style: inset; }
p.outset {border-style: outset;}
p.none   {border-style: none;  }
p.hidden {border-style: hidden;}
p.mix    {border-style: dotted dashed solid double;}

Interestingly enough, if you do not specify a color for the border via border-color then this will default to black.

The toplevel methods english() and german()

A couple of years ago these two toplevel methods were added. You may find some of my gems make use of these, when there is content that ought to be displayed on a website.

What do these two methods do, essentially?

They are mostly just a mnemonic reminder that the website that is shown to the user (visitor) is written in that particular language primarily. So, for most webpages, I prefer to use:

english() {

Whereas for my local knowledge base I often tend to use german.

Sometimes I mix both languages in the same webpage, but I wanted to be able to selectively switch between languages too, as well as be able to indicate when content is in german rather than english. Thus, to satisfy these use cases, german() and english() are available.

An additional use case for these methods is that I can designate a specific title quickly - either manually, or by using something like:


The symbol :autotitle here would mean that the cyberweb gem should try to infer the name of the page at hand based on its filename.


If you wish to make use of SVG it is recommended to install the svg_paradise project. Then, you can use it through Cyberweb such as in the following case:


This will output a SVG circle. Do note that this can be customized; simply have a look for the SVG Paradise project for more documentation pertaining to this part.

Drawing a coloured circle via CSS

You can draw a circle via CSS.

Let's first show the pure CSS rules for this functionality: {
  width: 300px;
  height: 300px;
  background: #2762e9;
  border-radius: 50%;

Next you can use HTML to actually "draw" the circle, as-is:

That's it.

I found this to be simple and potentially useful, so I added an API to the cyberweb project to support this.

The toplevel API goes like this:

Cyberweb.draw_circle(width: 200)
Cyberweb.draw_circle(width: 200, height: 500)
Cyberweb.draw_circle(width: 200, height: 500, background_color: :steelblue)
Cyberweb.draw_circle(width: 200, height: 500, background_color: :steelblue, border_radius: '30%')

Pass a Hash into the method. Note that this will return the CSS rule as-is, as well as return the div-tag String. Cyberweb::BaseModule will directly embed this if you use the method draw_circle().

Here is a partial screenshot showing three such examples; only the second example has a border-radius of 50%. See also the distributed example at cyberweb/examples/advanced/draw_circle/draw_circle.cgi showcasing this functionality.

class Cyberweb::ObtainCssRules

class Cyberweb::ObtainCssRules was added to quickly fetch the CSS rule shortcut.

For instance, the cyberweb gem comes with many custom CSS classes defined. I use these for different project.

One such CSS rule is this:

.mars1em {
  margin-left: 1em;
  margin-right: 1em;

Now: sometimes I can not use these custom CSS rules, even though I want to.

class Cyberweb::ObtainCssRules fills that use case.

We can tell this class to fetch the body of the CSS rule at .mars1em. This will then be automatically expanded onto the corresponding "margin-left" and "margin-right" entries.

To require this class do:

require 'cyberweb/utility_scripts/obtain_css_rules/obtain_css_rules.rb'

Furthermore, this class was also added to automatically make use of various shortcuts.

Let me demonstrate how I use this specifically.

In the file pidgin.rb, which is part of the roebe gem, I use the following:

default_template1 '

p.default {


What does the above mean?

It means that the p-tag (in HTML), if it makes use of the CSS class called default, will use the CSS rules defined in the .mars1em CSS class' body.

So, it is exactly identical to the following:

p.default {
  margin-left:  1em;
  margin-right: 1em;

This is a bit similar to less and SASS and similar shortcut-tools.

Within the web-app, for class WebObject, I may then create these paragraphs via:

p_default {
  e 'Hello world!'

Note that the above does not work 100% reliably; I added this in November 2022 in part to try it out.

In April 2023 this was improved a bit and changed slightly; I tend to use:

p_default_le {


At some later point in time this may be improved, so use with care. I recommend to be very strict when using the above functionality; the less complexity, the better usually (unless you can write more succinct and more expressive code, perhaps; but even then it is a trade-off ultimately).

Since as of April 2023 this functionality has proven to work fairly well, so tentatively I can recommend it now. All my local webpages make use of this already.

Returning all images from a remote website

If you ever have a use case that you wish to return all images found on a remote website, consider using the following API:

x = Cyberweb.return_all_images_from_this_webpage('', true)

This would yield the following Array:


Rack and the cyberweb project

Rack is a modular Ruby web server interface. It is very popular in the ruby ecosystem.

The most important method that rack requires is .call().

In May 2023 I tested whether Rack works for Cyberweb::HtmlTemplate and Cyberweb::WebObject - and it does. So we can now use, for instance, webrick, and have rack work automatically for these two classes specific to the cyberweb project.

In the long run I plan to smoothen this out, to make it possible to just use Rack directly rather than, say, sinatra or ruby-on-rails with the cyberweb gem.

Examples distributed in the cyberweb project

This subsection has a few noteworthy points to make about examples distributed in the cyberweb project.

You can find these examples under the directory called examples/ - easy to remember.

You can find plain HTML examples, and examples that use JavaScript and CSS. Additionally some examples stored as .cgi files are distributed as well, to demonstrate how the cyberweb project works. I recommend that you have a look at the simple examples first, without .cgi, unless you already know HTML/CSS/JavaScript, and then transition into the .cgi files. That should make it a bit easier to understand what is going on.

You may find that these examples sort of follow a specific style, more or less. For instance, I tend to name all animations with a trailing _animation tag. That helps me identify which animations exist more easily so.

JavaScript in general

The next subsection will contain some information about JavaScript.

JavaScript and JSON

To convert JSON to JavaScript the following function can be used:


To convert a JavaScript object to JSON, the following function can be used:


Variables in JavaScript

The three ways to declare a variable in JavaScript goes via var, let and const.

  • var variables can be updated and re-declared within their scope
  • let variables can be updated but not re-declared
  • const variables can neither be updated nor re-declared

Adding an Event Listener

The syntax in general goes like this:

button.addEventListener('click', call_function_here);

The above line would allow us to respond to a click-action. We could also use onclick="call_function_here()", but one advantage of using event listeners is that we can be more flexible, and even remove events again.

JavaScript comments

The simplest way to use comments in JavaScript, in my opinion, is via:

/* This is a comment */

JavaScript loops

To do a loop in "modern" JavaScript, try:

for (let i = 0; i < 5; ++i) {
  /* do stuff here */

The index variable i will remain completely local to the block, and not appear outside of it.

Note that JavaScript also allows you to use a .forEach loop instead, which no longer requires of you to use an index-counter.

There are a few variations possible for the .forEach() loop.

A somewhat verbose variant is the following one:

  function(entry) {
      "<img style=\"margin: 2px; margin-bottom: 5px\" src=\""+entry.replace(/^(\/home\/x\/data\/images\/fotos\/)/,"")+

Here we can easily use multiple lines.

A shorter variant exists via the => arrow.

Example for this:

array.forEach(entry => console.log(entry));

So this is basically like pp in ruby.

Checking for specific keys pressed, via JavaScript

You can obtain an event, and then call the method .code on it, such as via:

if (e.code === 'ArrowLeft') { # For the left-arrow key.
if (e.code === 'ArrowRight') { # For the right-arrow key.

Converting Strings to Numbers in JavaScript

To convert a String such as "5" to the Integer 5, use:

x = "5"

To convert a String such as "5.15" to the Float 5.15, use:

x = "5.15"

Numbers can be converted to a String via the method toString().

You can then also use the comparison operator, aka ===:

a = parseInt("3");
b = parseInt("5");
a === b

Setting a default value to a variable in JavaScript

let foobar = object.method1 || 'Default Value here'

Using the switch statement in JavaScript

Usage example:

case x:
  /* code to run when expression === x */
case y:
  /* code to run when expression === y */
  /* code to run if nothing else matches expression */

Symbols in JavaScript

To define a symbol in JavaScript, use Symbol() such as in:

let symbol1 = Symbol("mysymbol1")

String concatenation in JavaScript

The simplest way to concatenate two Strings in JavaScript is by using the + operator.

Example for this:

foobar = "foo" + "bar"

You can append to an existing String via the += operator.

Example for this:

foobar  = "foo"
foobar += "bar"

You can also use the method .concat(), such as in:

foo    = "foo"
foobar = foo.concat("bar")

Obtaining user input in JavaScript

The following code example shows how to obtain user input via JavScript:

var x, y;
x = prompt("Gib mal eine Zahl ein","")
y = prompt("Gib mir noch eine Zahl","")

So the primary way to obtain user through JavaScript goes via window.prompt. The second argument to that method specifies the default value of the input-field.

Creating an Array in JavaScript

The easiest way is the following:

const array = ['red','green','blue'] # This is also called the Array literal notation.

Note that at the least two additional ways exist in JavaScript to create an Array.

You can use:

The Array() constructor, aka:

new Array();


Functions that return arrays, such as split().

Note that you can, of course, also pass in elements into the Array when you create it via new. The following example shows this:

const array = new Array('January','February','March')

Personally I prefer the [] variant, as Ruby also uses it and I have become so used to it.

Appending and Prepending onto a JavaScript Array

The method .push() can be used to add content, via an append-operation, onto an array.


If you wish to add elements onto the beginning of an Array, use .unshift() such as via:

new_array.unshift("foobar"); /* Adds "foobar" to the beginning of the Array */

Splitting a String into an Array, in JavaScript

You can use the .split() method on a String, to split it up into an Array.

Example for this:

let x = 'Foo, Bar, Bla'
const splitted = x.split(',')

Simplified for-loop in JavaScript

You can iterate over an Array in JavaScript via:

const colours = ["Pink", "Green", "Yellow", "Black"];
for (const this_colour of colours) {
  console.log(this_colour); /* Display the element in the javascript-console */

Splitting an Array in JavaScript via the , delimiter

const new_array = old_array.split(',');

Shortcomings of JavaScript

This subsection lists some shortcomings of JavaScript. This may be subject to change, as JavaScript changes as well. It is not a rant as such either - the focus will be on syntax.

  • You can not use inline JavaScript if it contains the end part , such as:

    "); }

JavaScript support in the cyberweb project

The following subsection shows some of the javascript-related code and possibilities in regards to the cyberweb project.

The method .dump_all_javascript() in Cyberweb::WebObject

If you want to embed all javascript as a String and just put that string into the webpage, you can use this method call:


This is a bit hackish for now. The use case here was that a local .js file has to exist, in order for the browser to make use of it. For some reason this was not always the case on webservers I used - so, rather than invest more time to find the real problem, I simply added that method to be done with it and move it. That way I can still call custom javascript functions such as .toggle() and similar functions.

JavaScript for-in and for-of loops:

Just examples for each:

for (const key in {a: 1, b: 2}) {
// a, b

for (const value of [1,2,3,4,5]) {
// 1, 2, 3, 4, 5

Javascript-support in the Cyberweb project

Have a look at the subdirectory called javascript/.

If a new javascript-component is added, it should be registered in one of the .rb files in said directory.

Data Types in JavaScript (ECMAScript)

There are six simple data types:


How to use the typeof() operator in JavaScript

The typeof operator is called like this:

let x = "some string";
typeof(x)  # "string"
typeof(95) # "number"

Note that the () for typeof() could be omitted, as typeof is an operator and not a function - but it seems simpler to use the () just as it is used for other functions in JavaScript as well.

JavaScript clock

If you wish to display a small JavaScript "clock" that just shows the time, you could use this:

display_clock('pad1em') { :larger_font_size }

The block argument just increases the font-size a bit; it can be omitted of course, as can all arguments, too:


Specify JavaScript files

You can specify a specific javascript file via:

w.javascript_file = '../../CODE/JS/FADER.js'
w.javascript_file = :fader

As you can see, both a string version giving the full path, and a Symbol shortcut, will work - provided that the Symbol was registered.

I recommend to use the Symbol version for two reasons: first, it is less to type. Second, it is trivial to change the path lateron.

Removing child elements in JavaScript

An element can be removed via JavaScript by issueing:


Default parameters to functions in JavaScript

You can use default values to functions in JavaScript.


function multiply(a, b = 1) {
  return a * b;

console.log(multiply(5, 2));

Alternatively you could also use || inside of the function body, to simulate default values.

It may then look like this inside of a function:

bar = bar || "Default Value";

JavaScript's document.getElementById()

You can use JavaScript's document.getElementById() to modify values programmatically.

Example showcasing this:

function foobar() {
  document.getElementById("set_on_value_changed").value = "44";

All you need to know is the ID of the target element.

Does order matter for JavaScript?

Script tags that are used in a webpage are executed in the order they appear. So, if you look at the following JavaScript code:

var x = 42;

alert(x); // Will alert '3';

Then first the variable x will be set, to the value of 42.

Note that this also applies to when you load external .js files - first in, first to be evaluated. So order does indeed matter.

The reason I noted this down here was in the event that I may forgot why I decided to load some .js files before others.

There is, however had, also a practical consideration here: if you have some external .js files that take a while to load, it may be best to put them near the end of the page, or at the least after other .js files were already loaded, as it may otherwise slow down the loading of the webpage. This is the reason why some webpages recommend to put JavaScript script-tags shortly before the closing tag rather than in the section of the given HTML code at hand.

You can also use the async keyword; this means that the loading of the webpage will continue.


<script src="path/foobar.js" async></script>

JavaScript variables

The variables in JavaScript are by default global. You can make them local if you attach the var keyword to them.

You can also define several variables in one go, via:

var message = "hi",
found = false,
age = 29;

The keyword let has the lowest scope, even less than when compared to var.

Simple JavaScript Calculator



You may need to style the input-tag a bit.

See the following file for a working example:


It looks about this, by default (but remember you can customize it via CSS):

Showing a fancy CSS keyboard

If you use Cyberweb::WebObject then a fancy CSS keyboard can be shown. The method to do this is called:


Right now this is not too terribly useful, but I can imagine that this could serve as the basis to add an ad-hoc keyboard to a website, such as for smartphone users.

The progress bar in HTML5

You can use a progressbar to indicate progress based on percentage values. This is described here in more detail:

In cyberweb you can use the following API to indicate this:

progress('35 / 100') # this will display 35%

At a later time some javascript code may be added to indicate a counter-progress. Right now (as of February 2022) this is not possible though, so this part has to come at a later time.

The raw HTML code would look like this, for 35%:

<progress max="100" value="35"></progress>

If you want to style the progressbar then you have to use CSS. This can then be done via the progress[value] selector.

Example for this:

progress[value] {
  /* Reset the default appearance */
  -webkit-appearance: none;
  appearance: none;
  width:  250px;
  height:  20px;

New Tags in HTML5

This subsection is just a short summary; it may be incomplete, but that is ok as it mostly just serves as a short summary.

HTML5 introduced the following new tags:


# and probably:


Working with HTML forms, including creating input-buttons in such a form field

<input type="button" class="BG_GRAYSTD bblack1" value="Default" name="foo" onClick="test1(this.form)">

<input class="BG_GRAYSTD bblack1" type="button" value="Default" name="foo" onClick="test1(this.form)">

You can style ‹input> fields with a different background colour upon a mouse-focus event.

Examples for this would be:

input :text, 'Hello world!', :focus_with_salmon_background
input :text, 'Hello World!', :focus_with_salmon_background, :select_on_click

View the file at cyberweb/examples/simple/input_example_with_coloured_focus.cgi to see this work in action.

You can modify the ‹input> tag within that via css by using:

input.view_css {}

Note that ‹input type="text"> only works for a single line of user input. If you would like to have the user work via multiple lines then you have to use the ‹textarea> tag instead. There may be work-arounds, such as giving the text-input the word-break: break-word; attribute, but this may not work on every browser.

Some shortcuts exist within the Cyberweb project. For instance, rather than do:

input :checkbox

You can do:


Same with submit and other variants:


This may not be a huge improvement, but I wanted to offer it in the event that some users like to avoid using the : for the symbol.

Combining a label and input-text is possible via Cyberweb too. Examples:

label_and_input_text :foobar
label_and_input_text id: :foobar
label_and_input_text id: :foobar, :br
label_and_input_text id: :foobar, :linebreak
label_and_input_text id: :foobar, :middle_break
label_and_input_text :fname, 'First name:'

The last variant is essentially the same as this in HTML:

<label for="fname">First name:</label><br>
<input type="text" id="fname" name="fname"><br>

If you have a need or use case to use a checked checkbox then you can use a variant such as this:

checked_checkbox name: 'valid_ninja'

It may be important to specify the name parameter, as shown above; otherwise it can be omitted.

This checked checkbox looks about like this:

Use image-checkbox (on and off)


show_image_checkbox :on, 'posab','top:10em;right:18%'
show_image_checkbox :off, 'posab','top:10em;right:18%'

This is only useful for me and my home system. I have a few different science-specific subpages.

I can then link to these via:


This is quite plain, though, so I tend to add small images via:

science_links {{ use_this_image: dot109? }}

Other images could be supplied as well.

(Note that while this paragraph is for my own home system, the above could eventually be repurposed for other users too, if they have a bunch of external links they want to display on their homepage as well. I'll think about this for a while.)

Cyberweb::WebObject and the file

You can use a file called to automatically read in some settings for the web-object at hand.

The syntax is actually a .yml file.

cmd1, cmd2, cmd3, cmd4 and cmd5

The five methods called cmd1, cmd2, cmd3, cmd4 and cmd5 can be used to show commands that the user can input; or otherwise points at important content in a paragraph.

The 1, 2 or 3 part refers to the indent-level, so the number 3 means 3x the basic indent level.

The default indent is "mars2em", which is the class I use to denote:

margin-left: 2em;
margin-right: 2em;

So that is the default padding I tend to use among my own web-related ruby code. But, fear not, this can be changed by the user at-will, for any given webpage - thus allowing users to customize this, if they want to.

Note that cmd is an alias to cmd1. cmd in turn originated from command, and historically I used this method to display linux-specific commands, to allow me to understand how to operate on a linux system effectively.

In the last ten years or so, the code for this was stored under the module PredefinedMethods, but in December 2021 this was changed and became part of internal_hash.rb instead. The latter shall slowly replace all other toplevel-instance variables for the Cyberweb project. The net gain will be that the new code is easier to maintain.

In January 2023 the old :cmd entries were removed from internal_hash.rb and put into a new class, called Cyberweb::Cmd. This is the base class for Cyberweb::Cmd1, Cyberweb::Cmd2 and so forth. I believe this arrangement makes it easier to maintain the new code; the old code was also polished as it was ported into the new structure.

What is the use case for cmd1 or cmd2 or cmd3?

See the following example for this:

e 'Input these instructions:'
cmd1 'ls -la' # This is actually cmd1() but we can omit the () in ruby. \o/
cmd2 'cd /tmp'
# and so forth

So here we output a small span-tag, "Input these instructions:", and then we simply show these commands to the user via indented level - cmd1 is first indentation level, cmd2 is the second one, meaning an indentation level of margin-left: 3em, and so forth.

cmd1() will use a CSS class such as marl1em, which is an abbrevation used by the cyberweb gem to mean margin-left: 1em. All cmd() calls will also make use of the CSS class BOLD, which simply makes the text bold (that is font-weight: bold).

Note that you can customize the toplevel CSS used for cmd1, cmd2, cmd3, cmd4 and cmd5. The following example shows how to add the steelblue colour to these five entries:

append_to_cmd1 'steelblue'
append_to_cmd2 'steelblue'
append_to_cmd3 'steelblue'
append_to_cmd4 'steelblue'
append_to_cmd5 'steelblue'

However had, only do this when you really want to change the default CSS code there.

In March 2023 a convenient alias was added that combines this functionality. If you want to add such a colour, like steelblue, then you can simply call this toplevel method instead:

Cyberweb.append_to_all_cmd 'steelblue'
Cyberweb.append_to_all_cmd :steelblue # Or this variant.

This is exactly identical to the five lines above, the ones starting with append_to_cmd.

If you do not want to change the default CSS class but instead build upon it, then you can make use of the following variant:

cmd2 '  ls -l', append: 'gold BOLD'

So, simply use a Hash as the second argument here, with the keyword :append. The above is equivalent to:

cmd2 '  ls -l', { :append => 'gold BOLD' }

But easier to type.

You can designate other default CSS values, such as by doing the following:

Cyberweb.css_for_cmd  = 'marl1em steelblue BOLD'
Cyberweb.css_for_cmd2 = 'marl5em steelblue BOLD'
Cyberweb.css_for_cmd3 = 'marl8em steelblue BOLD'
Cyberweb.css_for_cmd1 = 'marl1em steelblue BOLD' # this works too; it is the same as the first variant

This also works for Cyberweb::WebObject, via wrapper methods.

The following wrapper methods will call the method defined above:

css_for_cmd1() css_for_cmd2() css_for_cmd3() css_for_cmd4() css_for_cmd5()

So for instance, css_for_cmd5() would invoke Cyberweb.css_for_cmd5 =.

Databases and the cyberweb gem

For now dealing with databases is super-primitive. This may be extended in the future.

If a file called database.sql is available in the current directory then the content-entry may be displayed by default, by calling try_to_honour_database_file(). At a later time this may be automatic; for now it has to be called manually.

Output generated by the cyberweb project, in particular by the web-object

This subsection was added in January 2023, because I had to rewrite some old functionality, to suit a new use case. This will be explained next.

Before 2023, the two methods that were in use by Cyberweb::WebObject were:


# and


ee() was just an alias over print, in the sense that it would call the method .add() directly, without modifications. .add() will simply add the given input to the html-string variable of the WebObject. This is the string that contains the content of the webpage, e. g. all content of a .html page (or rather, its equivalent).

e() on the other hand is more important and it is used primarily to generate output. This method will yield a span-tag, and add a br-tag afterwards. This worked very well for my own use cases in the last 15 years or so.

However had, starting in 2020, I was putting more and more content into projects that cyberweb has to render and handle. In particular, one use case I found to increase in the last 2 years (so from 2020 to 2022) was to use paragraphs such as this:

p_default {
  e 'Hello world!'

This would generate the following HTML string:

<p class="default">
<span>Hello world!</span>

For short paragraphs this is ok, but for longer paragraphs things can become a bit messy. It is harder and harder to read the content, in particular when there is a lot of text. So, naturally, to help space things a bit, I would transition to use this instead:

le 'Hello world!'

This is exactly as:

e 'Hello world!'

but it is making use of a CSS class called "padl2em" (or "padlem"). This CSS class will have a padding on the left hand side, e. g. "padding-left: 2em".

However had, changing all e() calls to le() calls for every single paragraph is cumbersome, so I wanted to have an alternative to this.

Thus, in January 2023 I decided to re-arrange the code, and add a new padding-call.

So, the following variant will make use of e():

p_default {

If you want to use le() instead (the variant for left-padding) then the following variant can be used:

p_default_le {

At a later point in time this may be revisited. For now this has to suffice.

Note that I am currently (2023) contemplating change the behaviour of ebr(). ebr() was the old legacy function what e() does nowadays. My idea is that ebr() first calls e() and then br() (aka append a br-tag). I have not yet decided on this though - need to test it first.

In April 2023 the above was improved a little. You can now add CSS rules such as important_mars3em. This has the !important part appended; mars3em means "margin-sides: 3.0em", which is "margin-left: 3em;" as well as "margin-right: 3em;".

Using !important is not ideal, but sometimes you may have to use it - for a single web-page this should be ok mostly.

Context menu when clicking on a page via the right-mouse button

Various websites offer a on-right-mouse-button-click-event open a context menu. For instance, Google's GMAIL does that.

The subsection here shall gather information how this is done; and then, eventually as a second step, to showcase how the cyberweb gem may be useful here.

So, first things first - let's explain what is needed.

The functionality requires some JavaScript code. Typically this occurs via an event-listened that is added onto the document.

The following snippet shows the basic JavaScript code that should be used for this functionality:

if (document.addEventListener) {
  document.addEventListener('contextmenu', function(e) {
    alert("Opening the context menu next"); // Here insert the code logic for your own menu.
  }, false);
} else {
  document.attachEvent('oncontextmenu', function() {
    alert("You've tried to open context menu");
    window.event.returnValue = false;

The meta tags in the <head> section

You can use various meta-tags in HTML. They will have to go into the <head> tag.

For instance, the following meta tag tells the browser that the charset to be used is Unicode (UTF-8):

<meta charset="UTF-8">

The use case for meta tags is to carry additional information. For instance, the name-attribute description would show up in search engine results.

The following subsection will just show some more meta-tags, without explaining them though:

&lt;meta charset="UTF-8">

   <meta name="description" content="Some webpage about something.">    <meta name="author" content="Unknown">

Showing snowflakes on the webpage

If you wish to show snowflakes on your webpage, do append this onto the URL:


Class Selectors in CSS

A class selector is used to apply styles to a specific HTML element.

The beginning of the class selector name must be a dot. The following example shows this:

.highlight {

    background-color: steelblue; }

Now this class selector rule can be used:

<h2 class="highlight">

    This is a header.


Cyberweb.localhost? will simply return the String 'http://localhost'.

This is only useful if you want to quickly test something on your own localhost (local webserver). I had to build "local" URLs and did not want to preface manually via 'http://', so it was easier to use a simpler method instead.

The viewport in a webpage

The viewport is the portion of a webpage that the user can see.

This can be specified as a meta tag, such as shown by the following example:

<meta name="viewport" content="width=device-width, ­initial-­scale=1">

The Box Model in CSS

Let's first look at an image explaining the Box Model in CSS:

In this image, content refers to the content of the HTML Tag at hand, such as the <p> tag.

HTML elements can be considered as boxes. The CSS box model is essentially a box that wraps around every HTML element, as shown in the image above.

Around the content are various layers:

  • the first is padding
  • next comes the border
  • finally we have margin

HTML forms

The following subsection will detail some useful knowledge about HTML forms.

HTML checkbox

The following HTML code shows how you can use a HTML checkbox:

<input type="checkbox" name="mainoption1" value="Starter">
<label for=" mainoption1">This text will appear next to the checkbox</label>

Objectified HTML Tags

Objectified HTML tags are something like this:

puts'hey there') # => "<span>hey there</span>"
puts'hey there').align_to_the_left # => "<span style="text-align: left;">hey there</span>"

In other words we may treat HTML tags as strings that can be embedded. The idea for this has been inspired by ruby-gtk, such as:


I needed to add a lot of OOP-centric methods to the cyberweb framework. Objectified HTML tags may solve this issue.

As of now in September 2021 this is, however had, experimental. In due time it will be evaluated whether we could enable these tags for use in a unified code base in the future. Stay tuned.

In late September 2021, the textarea-tag was added.


textarea ='content')
# You can also use this instead:
#   textarea = html_textarea
textarea.class = 'rounded_border_6px bblack1 FS2em pad8px' = 'ask_a_question' = 'ask_a_question'
textarea.rows = 6
textarea.cols = 90

Again - this is all highly experimental, but in the long run all HTML tags will become objectified, as an additional option. You need to decide for yourself whether you want to use this or not; the one-line approach in regular HTML is probably shorter.

The following table, sorted alphabetically, shows the currently (February 2022) available objectified HTML tags as part of the cyberweb project. More may be added in the future.

Name of the HTML tag Implementation Status True HTML tag
a added yes
abbr added yes
blockquote added yes
body added yes
button added yes
canvas added yes
cite added yes
combobox added no
details not yet added yes
div added yes
embed added yes
fieldset added yes
figure added yes
form added yes
head added yes
h1 added yes
h2 added yes
h3 added yes
h4 added yes
h5 added yes
h6 added yes
hbox added no
img added yes
map added yes
meta added yes
object added yes
p added yes
pre added yes
progress added yes
span added yes
table added yes
textarea added yes
title added yes
window added no

Note that some of the above, such as window, hbox or combobox, are not directly HTML tags. Nonetheless these were added, largely to improve compatibility with ruby-gtk3 and other toolkits that make use of a more object-centric nature in how to handle such entities. Some aliases may exist to "simulate" dealing with "real HTML tags".

Table is a bit special in that you can feed it an array, and it will generate the proper entries and entries - so it is a bit of a "meta"-tag in this regard.

You can also do some ad-hoc trickery with this.


_ = html_image('../../images/foobar.jpg')
_.css_class 'bblack3'
_.on_mouse_over {{

  upscale: '+50%',
  delay:   1.0 # in seconds

e _

This would embed the image called foobar.jpg into the current website, and add an upscale effect of +50% when the mouse hovers over it.

This is not yet ideal; I am experimenting. But in the long run I want to try to combine an OOP approach for the www with the old variant that cyberweb used in the last 15 years. It is a bit too verbose for my taste still, but eventually I should have ironed this out.

Let's have a look how we could use an objectified table.

Raw example:

alias e puts
table =
) = 'hover_transition'
table.css_class = 'rounded_border_8px wid100 bblack2'
table.css_style = 'font-size: 3.5em'
# We can even add headers:
table.headers  = %w( Month Savings )
e table # And output it here.

The above code will generate:

<table class="rounded_border_8px wid100 bblack2" id="hover_transition" style="font-size: 3.5em">

You could then either embed this into HTML, or simply use it from a ruby file - be it sinatra, a .cgi file or anything else.

In the long run I plan to add a lot more methods to these objectified HTML tags, if these are useful. The idea is that we can treat web-pages as distinct objects, with convenience features that make creating such objects simpler.

It is also planned to eventually replace the more complicated "legacy" code in the WebObject or toplevel-namespace of Cyberweb to make more use of such objectified HTML tags - in particular for the more advanced use cases.

You can use some custom javascript code too.

For example, if you want to have a div where the user can select the whole content of said div-tag on a left-mouse-button-click event, consider using code such as the following:

div ='<h2>Hello world!</h2>') = 'test_div'
div.on_clicked { :select_everything }

Note that this requires an ID. See the file select_everything_example.cgi for a variant that works on my home setup.

You may also use some shortcuts here and there. For example, if you look at the above last line, the div.on_clicked { :select_everything } variant, then you could also simplify this a bit towards:

div.on_clicked_select # Or this variant.

This is literally the same as the variant above, but you can use fewer characters to do the same. Sometimes less is more - but always think about whether you want to prefer the more succint variant; sometimes the longer variant is more readable, in particular when you come back to a project many months lateron. Note that right now, in October 2021, only some javascript-driven actions are added. This will be slowly extended, and then documented here as well.

You can respond to on-mouse-hover events via JavaScript too.

Consider the following div variable, assigned to an objectified HTML tag, as outlined above.

Now you use:

div.css_class = 'BG_Black white'
div.on_mouse_hover {{ bg: :orange }}

This would make the background of that div tag black (as specified by the CSS rule called BG_Black, which is distributed in the cyberweb project), and then, on a mouse-hover event over that div change the background of the whole div to orange. When the user moves the mouse cursor away the old colour is reinstated again.

Some of the functionality of the Objectified::HtmlTags is tested via the file cyberweb/test/complex_tests/testing_objectified_html_tags.rb.

Support for the canvas tag was added in October 2021. The canvas tag allows us to draw arbitrary objects onto the browser.

Note that you can mix Cyberweb::WebObject with objectified-html-tags.

For instance:

entry_for_the_name_of_the_card = html_input
entry_for_the_name_of_the_card.css_class = 'bblack2 pad8px'

  'Name of the card: ',entry_for_the_name_of_the_card.string?

This would put an input-tag into the second entry at the table.

The next example shows how to add a button that, on mouse hover event, changes its colour to lightblue:

button = html_button
button.text = 'Save'
button.css_class('larger bblack2 pad4px marl6em mart1em pad5px s1em')
button.on_hover_colour(:lightblue) # This currently does not work for all HTML colours, but it works for :lightblue.
addnl(button.to_s) # This line is currently needed if you use WebObject; in the future we may be able to skip having to do this.

In November 2021 I am still experimenting.

Consider the following ruby code for the objectified HTML tag:

_ = html_h1('Batterien')
_.css_class 'martb1px hover_pulse_grow'
ee _.result?

Alternatively this slightly shorter variant:

_ = Cyberweb.oop_h1('Batterien', 'martb1px hover_pulse_grow')
ee _.result?

This will add a HTML h1 tag, with some special CSS that allows for pulsing growth. The number 8 means 8 iterations, so 4 times growing up (because every step, forward and reverse, counts as +1).

I am not yet very happy with the above. It's still too verbose for my taste - but the good thing is that we actually auto-generate CSS here. That way we do not have to carry specific .css files - we simply autogenerate them anew.

Objectified HTML Tags versus the default class-based HTML Tags

You may have noticed that there are two groups of classes that are similarly named.

For example:




The first variant is older; at this point it is almost 10 years old. The latter variant is newish, about 1 year old or even less than that (as of October 2021).

So, which variant to use?

Well, right now the behaviour is not identical, and they have different use cases. Perhaps in the future I may unify towards objectified HTML tags, but for now the two will have to co-exist.

Whenever possible I will update the older variant, e. g. Cyberweb::Table, to tap into functionality that is made directly available within Cyberweb::Objectified::HtmlTags::Table, to give an example.

So, perhaps in the long run, all unique functionality that is currently made available by Cyberweb::Table and similarly named classes, may be found under the objectified HTML tags. The latter is more robust, IMO, and has more flexible use cases.

Animated Border Gradients in CSS

First, have a look at the following codepen:

A static image of the animated border, shown on the codepen linked in above, can be seen next:

I liked that result and decided in April 2023 that this would be nice to have available as part of the cyberweb gem.

Thus, a method was added that can generate some CSS code for this. This is not ideal or elegant (the code is a bit messy), but we can get the job done nonetheless.

Currently the method that we will use will generate a CSS class is called:

.animated_border_gradient_box {

So you have to use this CSS class on an element that you want to have a fancy, animated CSS border. You have to use that for the CSS class (that is .animated_border_gradient_box) - for instance, by attaching it to a div-element.

Example for this in regards to the cyberweb project:

div(css_class: 'animated_border_gradient_box') {

The following toplevel method will generate the CSS rules here:

Cyberweb.return_animated_border_gradient_box() # This is an alias to the above ^^^ method.

Passing arguments to this method has to happen via a Hash. This is currently a bit cumbersome though:

Cyberweb.generate_animated_border_gradient_box(inner_border_size: '12px')

At any rate, for now the objective was to just add this method, and then move on to do other things. At some later point in time this may be revisited and subsequently improved.

The method accepts more options - for now have a look at the code, in cyberweb/toplevel_methods/css.rb. As said it may be improved lateron.

Embed youtube videos and videos in general

You can embed youtube videos, thanks to the MultimediaParadise project, by issuing this:

youtube_embedder '',250

The second argument tells us the width to use for this video.

More generally, to embed videos in HTML5, you can use code like this:

<video controls width="250">
    <source src="/media/cc0-videos/flower.webm" type="video/webm">
    <source src="/media/cc0-videos/flower.mp4"  type="video/mp4">

In April 2023 the old code was adapted a bit. I am not yet sure whether the video-HTML tag should be supported by the cyberweb gem, at the least for youtube videos. Right now the cyberweb gem will focus on iframes - this may be subject to change at a later point in time.

A CSS tutorial

The following subsection will include useful tidbits and knowledge bits about CSS. This will not be all-encompassing, but instead just focuses on knowledge about CSS that I may find useful again at a later point in time.

CSS Basics

This subsection keeps some general information about CSS, in the event I forget stuff, or need to look it up quickly, or other people may read something new.

A style sheet in CSS can be broken down into the following smaller bits:

 Style sheet

When more than one selector appears in the same rule, they are said to be grouped.

An example for grouping in CSS is shown next:

th, td { padding: 0 10px 0 0; }

Here is another example showcasing grouping in CSS:

h1, h2, h3 {

     text-align: center;      color: gold; }

You can space out the selectors onto different lines, such as via this way:

td {
  padding: 0 10px 0 0;

Use whatever style you prefer.

HTML elements may treat CSS-width differently. The

element, for instance, only expands horizontally to accommodate its data, which is also called "shrink-to-fit". The
element, on the other hand, expands horizontally as far as there is space, which is called "expand-to-fit".

If you encounter a CSS rule with a !important classifier then this rule can not be overruled. It became a fixed rule. See elsewhere in this document in regards to more information about this.

The hexadecimal notation #FFF is a short hand for #FFFFFF (which is actually white).

RGB values in CSS may also be represented using percentages.

Example for this:

body {
  background-color: rgb(50%, 50%, 50%);

A class-selector looks like this:

.foobar {
  margin: 10px 0; # And similar comments

The . indicates that we want to use a class-selector definition.

The above class-selector is valid for every HTML tag that wants to use it. You can limit this and confine it to only some elements.

For example, to limited this only to div-tags, use:

div.foobar {

Interestingly you can also chain class names together such as: {
  background-image: url(foobar.jpg);

This means that it will only apply to any element that has both foo and bar as classes.

ID selectors in CSS can be used like this:

<style type="text/css">
  #foobar {
    background-image: url(foobar.jpg);
<div class="planet" id="foobar">

The universal selector in CSS is an asterisk. When used alone, the universal selector tells the CSS interpreter to apply the CSS rule to all elements in the document.

An example showing this follows next:

* {
  font-family: Arial, Helvetica,sans-serif;

In CSS, descendant refers to an element that is a child of another element.

To target an element based on its ancestor the CSS should be written in this way:

div.foobar h2 {
  font-size: 18px;
  margin-top: 0;

CSS pseudo-classes are used to represent dynamic events, a change in state, or a more general condition present in the document that is not easily accomplished through other means. Unlike normal classes, pseudo-classes have a single colon before the pseudo-class property.

Some browsers will apply the :link pseudo class styles to all links. Therefore it may be prudent to define the same properties in :link and :visited, so that the correct styles are applied.

For keyboard-focus you can use the pseudo-element :focus:

a:focus {
  text-decoration: underline;

CSS's background-image property

Most folks who relate to the world wide web will eventually come to know the CSS background-image property. You can designate a background image to be used for a website.

However had, that property is more useful in general. It can even be used to designate a colour-gradient.

The following example shows this:

background-image: linear-gradient(to bottom right, #95d9f9, #ae4bc3);

I found this quite convenient, so in April 2023 I decided to add support for this directly onto class Cyberweb::WebObject.

The syntax will be this:

left_to_right_gradient :steelblue, :lightgreen

This will be equivalent to the following CSS code:

background-image: linear-gradient(to bottom right, steelblue, lightgreen);

For an example of this in action have a look at the file cyberweb/examples/advanced/background_gradient_colour_example/background_gradient_colour_example.cgi.

Bold text in CSS

In CSS, normal text usually equates to a font-weight value of 400 whereas bold text equals to a value of 700.

CSS Animations

CSS Animations are defined by keyframes. Keyframe properties allow us to achieve perpetual animation effects.

Typically two transitions use used here:

  • The keyframe for the starting value.
  • The keyframe for the ending value.

The general syntax goes like this:

@keyframes name_here {

Opacity in CSS

Opacity can be set to a decimal value. In this case, 1 is equal to 100% opaque, whereas 0 means invisible.

Opacity can be set in increments between 0.0 and 1 with lower values being more transparent.

CSS support in the Cyberweb project

CSS colour gradient

You can "create" a colour gradient via:

colour_gradient_left_to_right(:steelblue, :darkgreen)

The third argument will be the name of the generated CSS class, defaulting to .gradient1.

You can then use this in a div-element like this:

  colour_gradient_left_to_right(:steelblue, :darkgreen)

# And then later:
div('gradient1') {
  h4 'Hello'

Global CSS classes in the Cyberweb project

In general, every HTML tag has a representative ruby class, with the first character being upcased.

For example, the div tag can be accessed, in some ways, through class Div. An example follows next.

Say that you wish to colourize all div tags on the given webpage with the colour red. The following code will do that:

Div.set_css_class 'red' # Now all divs are red.

This will still require a CSS class defined called .red, which has the content { color: red; }. However had, in a future release, Cyberweb may do this automatically, at the least for colours (we need to keep in mind that code should not be ambiguous).

The point of the above code is to provide you with a simple way to quickly style all HTML tags in some way. You may not want to find this too overly useful, but at the least the functionality exists for when you may need this.

Do note that you can remove the above via:



This works for all HTML tags by the way, for when it makes sense for such a tag to have that possibility.

An alternative may be:

Cyberweb.clear :div

This would clear any predefined-css-class for any tag. Both Div.clear and Cyberweb.clear :div are equivalent - use whatever seems better or easier for you.

Let's give another example - say that you want to modify the default CSS class for the html table tag:

Table.set_css_class 'bblack5 pink_border3 marl2em mart1em'
Cyberweb::Table.set_css_class 'bblack5 pink_border3 marl2em mart1em'

(The second variant is necessary if you did not do include Cyberweb before.)

After this was done, you can always query the css class via:


In fact, this is used as default argument to arguments in method definitions (with the corresponding name of the html tag).

Cyberweb also has some pre-defined tags, and CSS classes that can be used across different projects.

One such method is cmd() - this originally stood for "command", and was used to display commands that the user could input into a terminal/shell, on Linux.

The method cmd() has a pre-defined CSS class that can be queried like this:

Cyberweb.css_for_cmd? # => "marl1em BOLD"

This makes use of some default CSS classes, which is quite convenient if you have to show code on a website. For more information pertaining to cmd(), cmd1(), cmd2() and so forth, please see to the appropriate other subsection in this document.

CSS support in class Cyberweb::WebObject

The following subsection will detail how CSS relates and is used in class Cyberweb::WebObject. Most users may use that class to create a webpage via the cyberweb project.

CSS templates in class Cyberweb::WebObject

CSS templates can be designated by assigning to a symbol, such as this:

w.css_style = :template1

The templates are stored in the cascading_style_sheets/ subdirectory.

Other templates are :default and :code.

Note that it is currently (2021) unsure whether templates will be expanded. They will probably be retained, but may have to be reviewed again to determine whether they are sufficiently useful or not.

Since as of 2023, it is more common to use this:


This will be equivalent to :template1. The advantage here, aside from a cleaner syntax, is that we can easily change this to another template, if we want to.

Default CSS classes in the cyberweb gem

The Cyberweb comes with some CSS classes pre-defined.

I am aware that not everyone may want this, but it is simpler to bundle the custom CSS-classes that I use into this project - both for my own personal use case, but also because other people may see how the project works. Furthermore, these CSS classes can be quite convenient, allowing us to make use of shortcuts to style elements on a given webpage.

We assume that you have successfully installed the Cyberweb project at this point. Now you can use the commandline executable called "cyberweb" to generate a new .cgi file.

Issue something like this:

cyberweb test.cgi

This will create a default skeleton file for your project.

The page will have a default title, and use a global <div> html tag for the main content. A prominent member of this main <div> will be a <h2> header.

Obviously you can get rid of this part and use your own HTML structure.

Note: The first line of that script should be the Shebang to your actual Ruby version.

The commandline way is recommended to generate a proper cyberweb-conforming .cgi file.

Several helper methods are available to make best use of all available HTML tags. They are bundled together in the subdirectory html_tags/ of the cyberweb project.

Go visit that page in your browser and it should work fine.

You can also use a simplified approach to this.

For instance, say you want to display all images in a given directory. The short way to do so would be:

#!/usr/bin/ruby -w
# Encoding: UTF-8
# frozen_string_literal: true
# =========================================================================== #
require 'cyberweb/autoinclude'

doc {
  h2 'Welcome to this project'

A more complex (but also deprecated and disfavoured) example would be the following one:

w.t = 'SELF_NO_EXT' # Disable Extension-name.
w.css_style = :template1 # Is shorter. The templates can be found in: CSS/default.css
w.fav = 'PC/RUBY/RUBY_FAVICON.png'
w.body_css_class = 's12px padt4px marpad2px VERDANAs'
w.body_css_style = 'background-color: #d3d2d1;'
w.font_size = 'def' # or something like: '0.9em'
# The following is optional - set background colour and an image:
w.background_color = '#ffffee'
w.background_image = 'NJOY/VeronicaZemanova_01.jpg'

div {
  # Your stuff goes in here.

You can see the difference - the second variant allows you to be more explicit, with more control, whereas the first variant attempts to infer from the given information what should happen.

Do note that the call to .t aka .title will be optional if you have set the configuration option set_title_automatically to true in the configuration file. If that one is set to true, then we will automatically set a proper title based on the filename.

Also note that you can pass more newlines into the method called "body_css_style" - we will simply remove these extra newlines as of April 2016.

If you wish to display all images from a certain directory, do this:

display_all_images from: 'home/x/images/njoy/'

To use Frames, do:


Or better specify both pages to use within the block: frameset('30,40') { 'FRAME_LEFT.html,FRAME_RIGHT.html' } frameset { 'FRAME_LEFT.html,FRAME_RIGHT.html' } Or even shorter: w.frame_left 'foo.cgi' w.frame_right 'bar.cgi' w.frameset

To use Markdown, do something like this here (markdown tag):

markdown # defaults to all .md files.

To use an autogenerated Sitemap, do (sitemap tag):

sitemap :h4, 'Schnelles Abnehmen'
sitemap :h3, 'oki dokie','marl1em','oki_dokie'
autogenerated_sitemap # or asitemap, to trigger the display of it

To use Textile, do something like this here:

textile '/home/x/data/PC/TEXTILE/test.textile'

To count, do:

list 'foo'
list 'bar'
list 'bla'
clear_list # Resets the list-counter again.

To display the environmental variables (CGI Variables), do this:


You can enable drag and drop functionality for HTML elements. Consider looking at the FEATURES document for a longer explanation - this section here mostly just covers syntax.

In order to enable dragging support, you must pass the ID of the widget into this method:

drag_and_drop :div_sitemap_table
drag :div_sitemap_table # shorter than above
drag :last_id           # even shorter than above - last_id is a general pointer.
drag 'drag_#NAME#'      # A generic macro, which enables drag-support
                        # for that specific ID in question.

For some methods an alternative approach exists in addition to that. You can simply pass a block with the Symbol :drag to it.

Example for that:

img('AUDIO/BOX.png','VAM','Box2') { :drag }

And yet another syntax style is this:


Note that you can also globally enable drag-support for every image used, by issuing something such as:


As part of the initializer to the web_object.

So, with a specific example, you can do this:

w {
  title 'Title of your webpage.'

Also note that this will automatically enable jquery. So in other words, you will need to have jquery support.

Whenever you use a tag, such as h2(), it will be registered as the last tag used. This can then be referred to, if you need it, through the method last_tag_used?. The ID will also be recorded, so you can refer to the last used tag with javascript and modify it at your leisure.

You can embed .pdf files as well, by doing:

embed_pdf 'foobar.pdf'

Also note that you can generate a .pdf document from the site, by doing:


Example if you have a local .cgi script:


You can also link from within a page to this pdf-generation, by doing:

a 'SELF?pdf','SELF',1

You can enable debug mode by appending ?debug after the .cgi part.


If you want to show the source code of a .cgi page, append:


This can be disabled in the configuration file. If you do not need this functionality, simply set the value there to false.

You can define a specific encoding/charset to use as part of the Cyberweb, by issuing:

charset :utf

Note that we simplify certain javascript "magic instructions".

For instance, if you use 'on_mouse_over_underline' then this will be translated into the corresponding javascript function.



The above means that, on a mouse-over event for this <h2> tag, we will underline the whole header.

You can add a resize-handle to any object, by prefixing the ID with resize_ - so for instance:

div('','resize_container') {
  h2 'Resize this element'

If you wish to "link in" images that reside in the same directory as your target .cgi file, you can use this method:

in_dir_image 'foobar.png'

JavaScript support for html-colours in the cyberweb gem

The Array could be obtained via:

<script src="/home/x/programming/ruby/src/cyberweb/lib/cyberweb/javascript_code/html_colours.js">

Or in a relative way:

<script src="../../../lib/cyberweb/javascript_code/html_colours.js"></script>

Font Awesome

In July 2023 I discovered font awesome. You can see its effects on the Gentoo Wiki page, for instance, at:

Look at the tip-section, where a small icon is displayed. This is actually font awesome.

My original idea was to extend this subsection here, but I realised I can distribute small icons within the cyberweb gem, so I opted to do so instead, rather than go with Font Awesome. Stay tuned in this regard.


class Cyberweb::HtmlTemplate can be used to describe (and ultimately generate) a .html file - that is, to fill this class with HTML-specific content.

Let's show a specific example how this may be used first:

require 'cyberweb/requires/require_the_html_template.rb' # This is the recommended way to require class HtmlTemplate.

  title: 'Status',
  body:  '<pre style="font-size:150%">'+

This would represent a "full" HTML page, as a String.

It is possible, since as of 18.06.2021, to pass CSS classes into this class, via the entry called css_classes:


For example, passing 'darkblue' to that key means that the CSS class 'darkblue' will be made available, which ultimately comes down to color: darkblue.

This functionality was necessary in order to pull in only the CSS classes that are used on a particular web-page generated or represented by class Cyberweb::HtmlTemplate. Take note that when this is used, then no local CSS files will be pulled in. So you have to decide what you want: a minimalistic variant of HtmlTemplates, or the full-sized variant which will be used by Cyberweb::WebObject by default since as of May 2023.

Various additional entries are available. For example, if you want to modify the css-style in use for the body tag then you can simply use the following variant:

body_css_style: 'background-color:#DFD1FF'

In the long run the goal here is to extend class HtmlTemplate in such a way that all html-generation used within the Cyberweb project can be handled by it.

You can also pass ad-hoc CSS style into it. Example:

  body:  _, # The content of <body> goes in here.
  css_style: '
    img {
      border: 8px solid #black;
      padding: 2px;
    ' # and ^^^ there you can put your CSS rules into class HtmlTemplate

Furthermore, you can pass in some ad-hoc javascript code via:


All this does is add the proper [script> tag to it.

You can also specifically add jquery support for the HtmlTemplate.

The following example shows how this can be done:

html_template = Cyberweb::HtmlTemplate[
  title:      'This is a test-page,
  body:       HtmlTags.p('Another test.','','','font-size:1.8em'),
  use_jquery: true # here we specifically enable jquery

puts html_template

You can also pass in a favicon to use such as shown in the following example:

  title: 'Current Time',
  body:  '<b>'+Roebe::Time.hh_mm_ss+' '+Roebe::Time.dd_mm_yyyy+'</b>',
  favicon: BeautifulUrl[:time_favicon]

Typing Cyberweb::HtmlTemplate[] is quite cumbersome, though. Since as of October 2022 a simpler toplevel API is available:

Cyberweb.html_template(body_content) # The String you pass here will be the body of the HTML page.

An alias exists for this method as well, called Cyberweb.template. However had, this may be changed in the future, I am not sure. Cyberweb.html_template on the other hand will be guaranteed to remain as-is.

Since as of May 2023 class Cyberweb::WebObject now uses HtmlTemplate as its base. HtmlTemplate was also massively extended to allow for that functionality.

In August 2023 class Cyberweb::HtmlTemplate was partially rewritten, due to a confusing bug. I now recommend that users no longer use Cyberweb::HtmlTemplate directly, but instead use the toplevel method Cyberweb.html_template(). Simply pass the hash into that method; a String will be returned as a result.

Supporting opal

Since as of August 2023, the cyberweb gem supports opal.

This is not yet polished or finished, but I already used opal to write ruby-code rather than javascript code.


In August 2023 I added a gradient-gallery.

This will generate - or rather, make use of - gradients that may look like this:

You can find the raw .html page for this at the following location:


class Cyberweb::ObtainFilesAndDirectoriesFromThisPath

class Cyberweb::ObtainFilesAndDirectoriesFromThisPath is the base class whenever we need to obtain files and directories from a given path. It was created in October 2023, to serve as a more flexible base class for other classes - in particular for class Cyberweb::ImagesToHtml.

class Cyberweb::ImagesToHtml

This somewhat inconspicuous class can take a directory (as input, such as a commandline argument), determine all images that can be found in said directory (such as .jpg files, .png files, .avif files, .gif files and so forth), and then create a .html page that has entries to each of these images, thus displaying them, via the img-HTML tag. In other words: this class can display local images, conveniently via an autogenerated .html file.

The class supports jquery drag operations on every image, so that the user can move these images via the mouse cursor, just for a better visual effect, and the ability to reposition the images, should the user desire to do so. I found the drag-and-drop support here quite convenient to have - you simply move the image if you want to. I consider this to be a nice feature that really should be made possible without jquery, but I digress here.

The primary reason why this class ( class Cyberweb::ImagesToHtml) was written was to quickly display images that you have made available locally, such as your collection of fotos. I did not want to use an image viewer when I could just view this in a .html page as-is; also because sometimes an image viewer is not available by default, such as on most windows installation or it takes too long to open it (on older computer systems). So being able to show such fotos via the browser was a must-have criterium.

In March 2022 the --videos commandline option was added. This is used to, rather than gather images, gather videos. That way you can have a local collection of video files and have them show up in the .html page, in your browser. Note that actual playback tends to be limited to .mp4 files - I could not get older .avi files to work, for instance. No idea if it is possible to do so or not, so preferentially try to make use of .mp4 files here. Since as of October 2023 I am doing this with my own collection of video files - they all have been converted into .mp4 files, via the x265 codec (

In May 2022 another commandline option was added to this class, called --html-table. This option will arrange the images in a HTML table layout, by default 2 images per row (used to be 3 images per row, but on smaller devices this is not a good default, so I reverted to 2 images per row).

You can use more or fewers rows though if you want to. For instance, to use 4 rows (such as for widescreen monitors), make use of the following commandline flag:

images_to_html --table=4 # for 4 rows.

I tend to prefer 3 or 2 images per row. 2 images for smaller monitors is useful; 3 images is the best, in my opinion. 4 images tends to be cluttered, and more than 4 is, again in my opinion. not really advisable.

In October 2023 class Cyberweb::ObtainFilesAndDirectoriesFromThisPath was added and became the base-class for class Cyberweb::ImagesToHtml. In the long run the idea will be that specialized subclasses may be added that deal with e. g. video files, or, more recently, .pdf files. In fact I had a use case to list all local .pdf files, and class Cyberweb::ImagesToHtml was not ideal for this job, so my idea was to have one base subclass, and then specialize via other classes, such as class Cyberweb::ImagesToHtml.

class Cyberweb::VideoToHtml

class Cyberweb::VideoToHtml can be used to create a standalone .html file that shows all video files in the current directory (and optionally also all subdirectories). This was added in November 2023, so some bugs may still persist for the time being.

Automatic clipboard button

class Cyberweb::HtmlTemplate has a method called .return_copy_to_clipboard_button().

This method can be used to insert a button into a webpage. When the user clicks that button a certain text will be inserted into the clipboard, such as when a user would normally do a copy-and-then-paste operation. In other words: the clipboard-button that will be generated via this method will simplify certain actions for a human end user.

I use it specifically in one web-application where I need to open a certain .yml file in my default editor. I simply click on the icon if I need to do so, and then paste this onto the terminal via the mouse middle-button click event. It saves me at the least one manual step; in the future I plan to simplify this further, if possible.

At any rate, the method has to be somewhat flexible, as we may need to specify a specific ID to be used with that button.

The method signature goes like this right now:

  use_this_value           = 'XXX',
  use_this_id              = 'clipboard_button',
  hide_the_input_field     = false,
  text_shown_on_the_button = 'Copy text',
  css_rules_for_the_button = ''

So the ID that is to be used will be the second argument to this method.

Since as of November 2023, based on this provided ID, a second ID will be generated and used for the button itself (normally that passed ID will be used for the input HTML tag). This automatic ID will prepend the String 'button_id_for_the_', so if you need to use CSS to style that element then you know where to look for. Right now you may have to view the source of the HTML webpage, to know the ID exactly, but eventually I will make this easier, to allow users to automatically style (and modify) CSS elements like this.

class Cyberweb::DownloadAllImagesFromThisWebsite

class Cyberweb::DownloadAllImagesFromThisWebsite can be used to download all images found on a website, be it remote, or a local website (e. g. a local .html file).

Unfortunately I broke it in November 2023. Will have to fix it, and probably rewrite it, anyway.

module WebBase

module WebBase was created before the project html_tags was started, and before objectified-html-tags were added. So in some ways this was a legacy-module.

In January 2024, the old code from module WebBase was integrated into the objectified HTML tags component. Then the old WebBase namespace was removed.

Note that as part of the rewrite, each individual class that is part of the module Cyberweb::Objectified::HtmlTags, will contain a toplevel instance variable called @css_class. This derived from the old code in WebBase, where we could specify a default CSS class to be used - which is now defined under @css_class. This can be accessed by the toplevel method .css_class?. (Should you discover a class that does not have this, consider it a bug; it will be added once reported.)

The old functionality in module WebBase, in where we could set a default CSS class, has been retained API-wise. Example for how to use this:

Cyberweb::Span.set_css_class 'padl5em green'

Keep in mind that internally this will delegate towards the Objectified namespace.

Useful quotes when designing websites and web-apps

The following subsection collects a few interesting statements - kind of "the poor man's wisdom" when it comes to web-development and software engineering in general. Do not take any of these at face-value 1:1 but feel free to use any of them them as a starting point for gaining new insights or generating new ideas.

Any good-enough decision that can be made right now is still better than any 'perfect' decision that may come in way too late.“

When you are creating a website, the primary goal as a designer should be to get rid of the question marks users have when visiting that site.“

The most important thing a designer can do is to understand the basic principle of eliminating question marks that a user has when visiting a website. Keep things simple.“

If you can not make something self-evident, you should at the least make it self-explanatory.“

If a web page is going to be effective, it has to work most of its beautiful magic at a single glance.“

The average visitor rarely spends much time reading all content on a given web page, so focus on designing fewer elements that can be easily navigated, without too much distracting clutter.“

If your design forces a visitor to incur a small learning curve, make sure that the added value from this design change leads to it being worth that additional learning curve.“

Clarity trumps consistency.“

Each webpage should have a clear visual hierarchy.“

Components in a webpage that are related logically should also be related visually.“

In order to make a website 'scan-friendly', make good use of headings having a larger font size. The headings should indicate what a subsection is about.“

When using a heading, make them visually somewhat closer to the section they belong to, rather than equally spaced to the preceding paragraph.“

If you need the visitor to make a difficult choice, provide as much guidance as necessary - but not more. Be succinct here and provide only the smallest amount of information that will help the user.“

Omit needless words. Vigorous writing is concise.“

Try to make everything on a web-site self-explanatory or as close to it as possible.“

„Navigation should ideally remain clear, simple, and consistent.“

It may be useful to consider using an identifier, such as a logo or an image, for the website, and display this e. g. on the upper left corner. This may help visitors identify where they are, in particular if they tend to use several tabs in their browser.“

If your website makes use of a menu-bar or navigation-bar, consider highlighting the current location that the user has or uses on that website.“

Ideally a website should convey the big picture, and make it clear what the site is about.“

The web can be considered a dynamic computing environment.“

Good design is easier to change than bad design.“

Build documentation in - don't bolt it on.“

If possible consider to use visual identifiers on the whole web-application at hand, to give visitors the right idea about this being a cohesive and integrated unit.“

Changing a website at a later time is not necessarily trivial. Some percentage of users that have grown accustomed to a layout will resist almost any kind of change, and even apparently simple changes often turn out to have far-reaching effects..“

Focus ruthlessly on fixing the most serious problems first.“

Make the best decision you can with the information you have.“

This subsection just keeps a few useful resources related to the world wide web: HTML, CSS, JavaScript, Routers, WebServers.

This may become obsolete and outdated over time, so don't expect all links to work or be very useful. It's just a random collection really, last updated in May 2021.

Fancy CSS Tricks and Hints:

CSS-text effects:

Various CSS Tricks:

HTML Tutorial (HTML for beginners): HTML Tutorial (HTML for beginners)

Self-HTML: Self-HTML

Fancy Scrollbars: Fancy Scrollbars

For a quick list (a table) of available HTML tags, you may want to visit:

Contact information and mandatory 2FA (no longer) coming up in 2022 / 2023

If your creative mind has ideas and specific suggestions to make this gem more useful in general, feel free to drop me an email at any time, via:

Before that email I used an email account at Google gmail, but in 2021 I decided to slowly abandon gmail, for various reasons. In order to limit the explanation here, allow me to just briefly state that I do not feel as if I want to promote any Google service anymore when the user becomes the end product (such as via data collection by upstream services, including other proxy-services). My feeling is that this is a hugely flawed business model to begin with, and I no longer wish to support this in any way, even if only indirectly so, such as by using services of companies that try to promote this flawed model.

In regards to responding to emails: please keep in mind that responding may take some time, depending on the amount of work I may have at that moment. So it is not that emails are ignored; it is more that I have not (yet) found the time to read and reply. This means there may be a delay of days, weeks and in some instances also months. There is, unfortunately, not much I can do when I need to prioritise my time investment, but I try to consider all feedback as an opportunity to improve my projects nonetheless.

In 2022 decided to make 2FA mandatory for every gem owner eventually:


However had, that has been reverted again, so I decided to shorten this paragraph. Mandatory 2FA may exclude users who do not have a smartphone device or other means to 'identify'. I do not feel it is a fair assumption by others to be made that non-identified people may not contribute code, which is why I reject it. Mandatory 2FA would mean an end to all my projects on, so let's hope it will never happen. (Keep in mind that I refer to mandatory 2FA; I have no qualms for people who use 2FA on their own, but this carrot-and-stick strategy by those who control the rubygems infrastructure is a very bad one to pursue.