material-design-esp8266

Serving pages with Material Design aesthetics from ESP8266 or ESP32

  • 5 min

[lll-main-image] We continue with the entries on the ESP8266 and ESP32 by seeing how to serve a page with Material Design aesthetics thanks to the Material Design Lite library.

We will refer to the ESP8266, but the same code is compatible with the ESP32, adjusting the library names. At the end, you have the code for both the ESP8266 and the ESP32.

We have dedicated several entries to see how to serve web pages from the ESP8266, and how to connect the frontend with the backend through AJAX or Websockets calls.

But, let’s admit it, the web pages we have served so far are quite ugly. That is about to change! and we will start with the simple Material Design Lite library we already saw in this entry.

So let’s get to work! Regarding the backend part, that is, the ESP8266 code, it is identical to the one we have been using. That is,

#include <ESP8266WiFi.h>
#include <ESPAsyncWebServer.h>
#include <FS.h>

#include "config.h"  // Replace with your network data
#include "Server.hpp"
#include "ESP8266_Utils.hpp"

void setup(void)
{
	Serial.begin(115200);
	SPIFFS.begin();
	
	ConnectWiFi_STA();
	
	InitServer();
}

void loop(void)
{
}
Copied!
AsyncWebServer server(80);

void InitServer()
{
  server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.html");

  server.onNotFound([](AsyncWebServerRequest *request) {
    request->send(400, "text/plain", "Not found");
  });

  server.begin();
  Serial.println("HTTP server started");
}
Copied!

The real difference in this example is in the ‘index.html’ file and in the files we will upload to the SPIFFS memory. Until now our html code would have been like this,

<!doctype html>
<html class="no-js" lang="">

<head>
  <meta charset="utf-8">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  <title></title>
  <meta name="description" content="">
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
  <div>
    <div>
      <form action="#">
        <div>
          <input type="text" id="sample3">
          <label for="sample3">Text...</label>
        </div>
      </form>
    </div>
  </div>

  <div>
    <div>
      <button>
        <i class="material-icons">add</i>
      </button>
    </div>
    <div>
      <button>Button</button>
    </div>
  </div>

  <div>
    <div>
      <input type="range" min="0" max="100" value="25" tabindex="0">
    </div>
  </div>

  <div >
    <div>
      <label or="checkbox-1">
        <input type="checkbox" id="checkbox-1" checked>
        <span>Checkbox</span>
      </label>
      <label for="checkbox-2">
        <input type="checkbox" id="checkbox-2">
        <span>Checkbox2</span>
      </label>
      <label for="checkbox-3">
        <input type="checkbox" id="checkbox-3">
        <span>Checkbox3</span>
      </label>
    </div>
  </div>

  <div>
    <div>
      <label for="option-1">
        <input type="radio" id="option-1" name="options" value="1" checked>
        <span>First</span>
      </label>
      <label for="option-2">
        <input type="radio" id="option-2" name="options" value="2">
        <span>Second</span>
      </label>
      <label for="option-3">
        <input type="radio" id="option-3" name="options" value="3">
        <span>Third</span>
      </label>
    </div>
  </div>

  <div>
    <div>
      <label or="switch-1">
        <input type="checkbox" id="switch-1" checked>
        <span>Switch</span>
      </label>
    </div>
  </div>
</body>

</html>
Copied!

Which would give this terribly ugly result.

material-design-lite-test-befor

And now it is going to become

<!doctype html>
<html class="no-js" lang="">
 
<head>
   <title>ESP8266 Material Lite</title>
   <meta charset="utf-8">
   <meta http-equiv="x-ua-compatible" content="ie=edge">

   <meta name="description" content="">
   <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
 
<body>
  <link rel="stylesheet" href="vendor/google-fonts.css">
  <link rel="stylesheet" href="vendor/material.css">
  <!--<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/material.indigo-pink.min.css">-->
 
   <div class="mdl-grid">
      <div class="mdl-cell mdl-cell--4-col">
         <form action="#">
            <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
               <input class="mdl-textfield__input" type="text" id="sample3">
               <label class="mdl-textfield__label" for="sample3">Text...</label>
            </div>
         </form>
      </div>
   </div>
 
   <div class="mdl-grid">
      <div class="mdl-cell mdl-cell--1-col">
         <button class="mdl-button mdl-js-button mdl-button--fab mdl-js-ripple-effect mdl-button--colored">
            <i class="material-icons">add</i>
         </button>
      </div>
      <div class="mdl-cell mdl-cell--1-col">
         <button class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--colored">Button</button>
      </div>
   </div>
 
   <div class="mdl-grid">
      <div class="mdl-cell mdl-cell--4-col">
         <input class="mdl-slider mdl-js-slider" type="range" min="0" max="100" value="25" tabindex="0">
      </div>
   </div>
 
   <div class="mdl-grid">
      <div class="mdl-cell mdl-cell--4-col">
         <label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="checkbox-1">
            <input type="checkbox" id="checkbox-1" class="mdl-checkbox__input" checked>
            <span class="mdl-checkbox__label">Checkbox</span>
         </label>
         <label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="checkbox-2">
            <input type="checkbox" id="checkbox-2" class="mdl-checkbox__input">
            <span class="mdl-checkbox__label">Checkbox2</span>
         </label>
         <label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="checkbox-3">
            <input type="checkbox" id="checkbox-3" class="mdl-checkbox__input">
            <span class="mdl-checkbox__label">Checkbox3</span>
         </label>
      </div>
   </div>
 
   <div class="mdl-grid">
      <div class="mdl-cell mdl-cell--4-col">
         <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="option-1">
            <input type="radio" id="option-1" class="mdl-radio__button" name="options" value="1" checked>
            <span class="mdl-radio__label">First</span>
         </label>
         <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="option-2">
            <input type="radio" id="option-2" class="mdl-radio__button" name="options" value="2">
            <span class="mdl-radio__label">Second</span>
         </label>
         <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="option-3">
            <input type="radio" id="option-3" class="mdl-radio__button" name="options" value="3">
            <span class="mdl-radio__label">Third</span>
         </label>
      </div>
   </div>
 
   <div class="mdl-grid">
      <div class="mdl-cell mdl-cell--4-col">
         <label class="mdl-switch mdl-js-switch mdl-js-ripple-effect" for="switch-1">
            <input type="checkbox" id="switch-1" class="mdl-switch__input" checked>
            <span class="mdl-switch__label">Switch</span>
         </label>
      </div>
   </div>
 
  <script src="vendor/material.js"></script>
  <!--<script src="https://cdn.jsdelivr.net/combine/npm/[email protected],npm/[email protected]"></script>-->
</body>
 
</html>
Copied!

With which we will achieve this aesthetic.

esp8266-material-design-formulario

Regarding the files used by the Material Design Lite framework (JS and CSS) we can either load them from a CDN, or upload them compressed to the ESP8266’s memory.

In the example you have both options, with the CDN option commented out.

In principle we will always prefer the CDN whenever possible, that is, when the end client has an Internet connection to download the files. This way we free the ESP8266 from the work of having to serve the files.

But this is not always possible. For example, we will have to serve them ourselves when the ESP8266 is acting in AP mode because the client will not have Internet access to download the files from the CDN.

It was that simple! Of course, we are using the Material Design Lite framework but you can use any other framework or template you want to serve the web pages following the procedure we have seen to load the files.

No more excuses for serving “ugly” pages from your ESP8266. In the next entry of the series, we will get back into frontend-backend communication by exchanging information encoded in Json in Ajax calls. See you soon!

Download the code

All the code from this entry is available for download on Github.

github-full

Version for ESP8266: https://github.com/luisllamasbinaburo/ESP8266-Examples

Version for ESP32: https://github.com/luisllamasbinaburo/ESP32-Examples