Web browsing in Emacs
Why would you want web browsing in a text editor?
Emacs has a tendency to try and absorb all user-facing interactions I have with a computer. Some people seem able to separate “Emacs stuff” — like programming or using org-mode for note taking — but Emacs’ extendability makes me want to use it for everything. For a long time I have only really needed four different tools to do any kind of work at a computer:
- GNU Emacs (with my personal config).
- Tailscale to connect to my other machines.
- Syncthing so that I have local access to my files1.
- A web browser (usually Firefox).
Quickly getting these four things up and running is usually my first
priority when setting up a new machine, and they require different
amounts of work. Critically Firefox requires a GUI environment in
order to run, but it’s really quite unnecessary to get a desktop
environment or tiling window manager up and running — and dealing with
their conflicting keybinds — when all I’m going to be doing is working
in Emacs perhaps 80% of the time, finding information or reading docs
in Firefox 15% of the time, and using a stray terminal the remaining
5% (something I can easily replace with one of Emacs’ many terminal
and shell solutions). This is why I like using exwm
2. Rather than
using Emacs’ window manager capabilities to manage all your X windows
it allows you to stay continually within Emacs and just treat any
stray non-Emacs GUI programs within the same system. The solution then
seems to try and subsume web browsing into my preëxisting
workflow. There are many solutions to this, but I prefer ones that
work with text as the primary medium as that is what Emacs is best
oriented to work with.
The Emacs Web Wowser (eww)
eww
is probably the most well-known of Emacs’ web browsing solutions,
chiefly because it comes included with it. It is also the one I have
the most experience with. I first came across eww
as a consequence of
reading about all of the crazy features included in Emacs by default
like Tetris and Gnus. This isn’t very surprising; web browsers are
some of the largest ubiquitous user-facing applications, so the fact
that Emacs ships with one as a tangential feature is very
surprising. However, these visions of browsing the web are often
quickly crushed when one uses eww
for the first time. It does not load
any CSS, so websites do not look like one is accustomed to, and a lot
of javascript functionality is non-functional.
I expect this experience — or at least something like it — to be
somewhat universal amongst those who have even tried using eww
. The
modern web is built around these technologies, and going without them
might seem almost impossible. But there is a place for eww
in a modern
workflow. The strength of Emacs is its power for working with text,
and most media I interact with in a web browser is text. Emacs then is
really the perfect environment for this. Reading and rewriting the
content of web pages side-by-side using the same key-chords and
user-interface allows for minimal context friction. But there are
serious downsides, primarily ugly formatted headers and images. Most
of the time eww
can figure out the main readable content using the
eww-readable
function, bound to R
by default. It’s meant to strip out
long “navigation menus and the like”. In my experience it is either
hit or miss. For some web pages like wikipedia it seems to work well
(but only for some pages), but for others like github it just strips
out the entire page. Thankfully it is bound to a convenient key and
its easy to switch between the two views quickly. Images are probably
one of the first things that stops people from using eww
, with large
ones causing the site to jump around as they cover the whole screen
and then disappear. I solved this using ultra-scroll, which provides
scrolling smoother than you could ever imagine in Emacs. It also
allows you to scroll intuitively over images, rendering them as you
would expect in a traditional browser like Firefox. With a slow
network connection eww
can have some problems with blocking, but this
can be remedied by setting eww-retrieve-command
:
(setq eww-retrieve-command '("chromium" "--headless" "--dump-dom"))
eww
is written by Lars Ingebrigtsen of gnus
fame. It uses the shr
(simple HTML Renderer) program written in elisp to render HTML. He
originally wrote shr
to read elfeed
entries in Emacs and eww
is merely
the addition of browsing (or wowsing) capability built on top of
it. shr
’s elisp nature is why it can sometimes struggle with
complicated site layouts, but in my experience it is usually fast
enough, especially with native compilation.
Generally eww
can be surprisingly powerful, but most of its power
(like Emacs itself) comes from its tight integration with other
tooling and extensibility with elisp, rather than any amazing workflow
it has built for you in advance. There is very little to learn, but a
lot to master.
w3m
w3m
can some sense be seen as the “hardcore” version of text-based web
browsing in Emacs. w3m
relies on the eponymous TUI program to render
web pages in a way similar to Lynx, allegedly the world’s oldest
continually-maintained web browser. w3m
even comes with lynx bindings
by default, although you can also change them to the included
“info-like” ones. It allows for tabs, bookmarks, and other features
one would expect in a modern browser. It also relies on interpreting
the raw HTML to format the page, rather than rendering CSS. Like eww
it also does not support javascript. Like I alluded to earlier, this
is both a blessing and a curse, and reading just straight text can be
very nice, both from a therapeutic minimalist way and a way to
minimize context-switching. It is also nice and async by default,
since it uses an external binary to fetch websites, not that it takes
very long to load to begin with since it’s not running any heavy
javascript. One nice difference between w3m
and eww
is also that
the arrow keys navigate to the next link in the page by default, and
the text in the buffer will resize itself whenever the buffer is
resized3, something that is very handy if you’re using a package
like golden-ratio that
resizes windows depending on focus.
Non-text based
While I prefer text-based browsers that fit more seamlessly into the rest of Emacs, there are other solutions for more traditional browser experiences.
Xwidgets
Since version 25 Emacs has had the ability to be compiled with
xwidgets support, and to render complete web pages through webkit. To
do this merely add the --with-xwidgets
flag to Emacs when compiling,
and then run M-x xwidget-webkit-browse-url
to surf the web! Sadly this
doesn’t work very well at the moment, as you’ll quickly realize if you
were to do the above. There is apparently a bug in the xwidget library
webkitgtk
that causes Emacs to abort. Worse yet its status is wontfix
since GNU Emacs seems to be the only program affected by it thanks to
its old and strange ways of doing things. Upon crashing Emacs links to
a 22 year old bug
report that had its last message sent five years ago, so I’m not
exactly holding out hope (but maybe a good project to work on for
someone?). It seems to work with version 2.40 of webkitgtk
so try
and use that if you’re having issues. Sadly I have not gotten it to
work but I keep seeing people mentioning xwidgets as an option so it
might work on some machines.
EAF
Getting a non-text browser in the text-based environment of Emacs requires working around Emacs’ systems. EAF (Emacs Application Framework) does this through creating an exterior python system that then hooks into Emacs to run a number of programs, chief among them a webkit-based browser.
The largest problem I have with the EAF’s browser is not really with
the browser itself, although it is a bit unstable, but instead with
the EAF itself. Being part of this large group of packages that feel
very external to Emacs they are troublesome to install and maintain as
part of a workflow. Installing EAF (something you’re probably only
doing for the browser) asks you individually if you’d like to install
things like a git client, system monitor, file browser, terminal,
multiple demos, and numerous other things. Some of these things are
impressive and useful, but I’d rather explicitly say what I’d like to
install instead of having a Y/N on each program. Imagine having to do
that for every ELPA package when first launching Emacs! EAF is of
course nowhere near that level, but it’s still a baffling design
decision. It also makes it way less portable, since I can’t describe
what EAF programs I want to install (although I can for which ones I
want to use) in a declarative way. It also has a few issues with
javascript that feel like deal-breakers for a graphical browser, I’d
rather go all-the-way with a text-based browser like eww
or use a
fully functional graphical browser like firefox.
Footnotes:
I can use tailscale to edit the files remotely using TRAMP
, but
that is usually pretty slow since my home network is very
unreliable. Much easier to just sync “asynchronously” when the network
feels like it.
exwm
has other issues, namely around multi-monitor setups. They
make sense and are probably sacrifices I would have made had I created
exwm
, but I don’t really like working with frames instead of
windows. It becomes another layer of friction, even if I’m still
working within Emacs.
To try and replicate this behaviour in eww
you have to run
(eww-reload t)
, by default bound to C-u g
, to refresh the buffer and
reformat it. You can probably run it in a hook whenever you resize
windows, but I don’t care to do that.