Tutorial

How To Build a Responsive About Me Page with Laravel, Sail, and Tailwind CSS

PHPPHP FrameworksDevelopmentLaravelCSS

Introduction

Laravel Sail is a Docker development environment included by default in Laravel since version 8. It allows you to quickly get a PHP development environment up and running, tailored for running Laravel applications with built-in support for NPM / Node.

In this guide, you’ll bootstrap a new Laravel application with Laravel Sail and create a styled “about me” landing page using Tailwind CSS, a utility-first CSS framework designed for rapidly building custom user interfaces. At the end, you’ll have a base that you can use to further develop a Laravel application using Tailwind CSS for the front end and Sail for the development environment.

Laravel Tailwind Responsive About Me Page

If you’d prefer to follow along from an existing codebase rather than creating the project from scratch, you can access the finished demo application code at do-community/laravel-tailwind-starter on GitHub.

Prerequisites

Although the code shared in this guide should work seamlessly across multiple environments and systems, the instructions explained here were tested within an Ubuntu 20.04 local system running Docker and Docker Compose. Regardless of your base operating system, here’s what you’ll need to set up in order to get started:

  • Docker installed on your local machine. If you’re running Ubuntu 20.04, you can follow Steps 1 and 2 of How To Install and Use Docker on Ubuntu 20.04 to set it up. Windows and MacOS users need to install Docker Desktop instead.
  • Docker Compose installed on your local machine. Docker Compose comes included by default with Docker Desktop for both Windows and MacOS systems, but Linux users need to install the Compose executable, following Step 1 of How To Install and Use Docker Compose on Ubuntu 20.04.
  • A code editor for PHP (optional). A code editor helps making code easier to read and to format, and can improve your productivity by pointing out issues before you execute your code. You can follow our guide on How To Set Up Visual Studio Code for PHP Projects to set up VSCode, a free code editor, within your local development environment.

Step 1 — Creating a New Laravel Application Using the Laravel Builder Script

To get started, you’ll download and execute the official Laravel builder script, which will pull in the necessary Docker container images to build your development environment and then bootstrap a new application in your current folder. This installation method doesn’t require you to have PHP installed on your system, requiring only that you download and execute the builder script that will set up the Docker environment where you can run the actual Laravel installer.

At the end, the script asks for your sudo password to make sure the application folder has correct permissions for your system user. You can access the script URL from your browser to verify its contents before running the next command. In this example, we’re using the name myapp, but you are free to replace this with a different name:

curl -s https://laravel.build/myapp | bash
Output
Unable to find image 'laravelsail/php80-composer:latest' locally latest: Pulling from laravelsail/php80-composer 852e50cd189d: Pull complete 0266fc315b01: Pull complete … Application ready! Build something amazing. Sail scaffolding installed successfully. Please provide your password so we can make some final adjustments to your application's permissions. [sudo] password for sammy: Thank you! We hope you build something incredible. Dive in with: cd myapp && ./vendor/bin/sail up

When the installation is finished, access the new application directory and get the Sail environment up with:

  • cd myapp
  • ./vendor/bin/sail up

This will bring the environment up in foreground mode, so you can follow up with the logs from all running containers. You’ll see a few different services getting started, using different ports to communicate between each other:

Output
... mailhog_1 | [HTTP] Binding to address: 0.0.0.0:8025 ... laravel.test_1 | Starting Laravel development server: http://0.0.0.0:80 ... meilisearch_1 | Server listening on: "http://0.0.0.0:7700" ... mysql_1 | 2021-06-23T01:15:24.327234Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.25' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL. ... selenium_1 | 01:14:57.417 INFO [SeleniumServer.boot] - Selenium Server is up and running on port 4444 ... redis_1 | 1:M 23 Jun 2021 01:14:54.243 * Running mode=standalone, port=6379. …

These are services configured by default within Sail environments. For more information about each of them, refer to the official Sail documentation.

Next, access the application from your browser at:

http://localhost

If all steps were successful, you’ll see a page like this:
Laravel welcome page

The application is now bootstrapped.

You can now stop the Sail environment that is running on your terminal by typing CTRL+C.

Step 2 — Using Laravel Sail

Laravel Sail offers several shortcuts to manage your development environment. Most commands and arguments are based on the default Docker Compose API.

Controlling the Environment

To bring the environment up in background mode, you can run:

  • ./vendor/bin/sail up -d

To stop a Sail environment that was previously initiated in background mode, run:

  • ./vendor/bin/sail stop

This won’t delete attached networks or volumes.

To bring back an environment that was previously stopped with a sail stop command, you can use:

  • ./vendor/bin/sail start

To stop an environment and also delete all associated resources such as volumes and networks, you can use the sail down command. Please notice that this command will delete any data that was previously created and is only available inside containers, such as records stored in a database.

  • ./vendor/bin/sail down
Output
Stopping laravel-tailwind-starter_laravel.test_1 ... done Stopping laravel-tailwind-starter_redis_1 ... done Stopping laravel-tailwind-starter_selenium_1 ... done Stopping laravel-tailwind-starter_mysql_1 ... done Stopping laravel-tailwind-starter_mailhog_1 ... done Stopping laravel-tailwind-starter_meilisearch_1 ... done Removing laravel-tailwind-starter_laravel.test_1 ... done Removing laravel-tailwind-starter_redis_1 ... done Removing laravel-tailwind-starter_selenium_1 ... done Removing laravel-tailwind-starter_mysql_1 ... done Removing laravel-tailwind-starter_mailhog_1 ... done Removing laravel-tailwind-starter_meilisearch_1 ... done Removing network laravel-tailwind-starter_sail

Checking Status and Logs

If your environment is down, bring it back up with:

  • ./vendor/bin/sail up -d

When your environment is up and running, you can check the status of all active containers with:

  • ./vendor/bin/sail ps
Output
Name Command State Ports --------------------------------------------------------------------------------------------------------------------------------- myapp_laravel.test_1 start-container Up 0.0.0.0:80->80/tcp,:::80->80/tcp, 8000/tcp myapp_mailhog_1 MailHog Up 0.0.0.0:1025->1025/tcp,:::1025->1025/tcp, 0.0.0.0:8025->8025/tcp,:::8025->8025/tcp myapp_meilisearch_1 tini -- /bin/sh -c ./meili ... Up (healthy) 0.0.0.0:7700->7700/tcp,:::7700->7700/tcp myapp_mysql_1 docker-entrypoint.sh mysqld Up (healthy) 0.0.0.0:3306->3306/tcp,:::3306->3306/tcp, 33060/tcp myapp_redis_1 docker-entrypoint.sh redis ... Up (healthy) 0.0.0.0:6379->6379/tcp,:::6379->6379/tcp myapp_selenium_1 /opt/bin/entry_point.sh Up 4444/tcp

The output from the sail ps command will tell you which containers related to that specific environment are currently active, which ports are being redirected, and more importantly, in which state each container is. In the previous example output, all services are up.

To check the containers logs when you’re running your environment in background mode, you can use:

  • ./vendor/bin/sail logs

This will show you the latest logs from all services.

Attaching to laravel-tailwind-starter_laravel.test_1, laravel-tailwind-starter_mailhog_1, laravel-tailwind-starter_mysql_1, laravel-tailwind-starter_redis_1, laravel-tailwind-starter_selenium_1, laravel-tailwind-starter_meilisearch_1
...
mysql_1         | 2021-06-24T15:08:06.435530Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.25'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server - GPL.
...
meilisearch_1   | [2021-06-24T15:16:38Z INFO  actix_web::middleware::logger] 127.0.0.1:60874 "GET /health HTTP/1.1" 200 22 "-" "Wget" 0.000056
...
laravel.test_1  | [Thu Jun 24 15:08:07 2021] PHP 8.0.7 Development Server (http://0.0.0.0:80) started
...

selenium_1      | 15:08:06.864 INFO [SeleniumServer.boot] - Selenium Server is up and running on port 4444
...
redis_1         | 1:M 24 Jun 2021 15:08:05.280 * Ready to accept connections
...
mailhog_1       | 2021/06/24 15:08:05 Serving under http://0.0.0.0:8025/

You can also see logs per service by providing an additional argument to the command call:

  • ./vendor/bin/sail logs redis
Output
Attaching to laravel-tailwind-starter_redis_1 redis_1 | 1:C 24 Jun 2021 15:08:05.278 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo redis_1 | 1:C 24 Jun 2021 15:08:05.278 # Redis version=6.2.4, bits=64, commit=00000000, modified=0, pid=1, just started ... redis_1 | 1:M 24 Jun 2021 15:08:05.280 * RDB memory usage when created 0.77 Mb redis_1 | 1:M 24 Jun 2021 15:08:05.280 * DB loaded from disk: 0.000 seconds redis_1 | 1:M 24 Jun 2021 15:08:05.280 * Ready to accept connections

Running Artisan and Composer

While working on your Laravel application, you’ll often be required to run artisan commands to build, test, and manage your application. You’ll also need to run composer commands to manage your PHP dependencies. In addition to the default Docker Compose API, Sail offers helpful shortcuts to execute these commands in your application container (myapp_laravel.test_1 in the example output). With a regular Docker Compose setup, running Artisan would look like this:

With Docker Compose Only
docker-compose exec app php artisan

With Sail, the equivalent call is shortened to:

Running Artisan With Sail
  • ./vendor/bin/sail artisan

You can run Composer in a similar way:

Running Composer With Sail
  • ./vendor/bin/sail composer

For more information about all features and commands available, please visit the official Laravel Sail Documentation.

You’re now familiar with how to manage your Sail development environment and how to run commands on the application container. In the next step, you’ll set up Tailwind CSS to design and style your landing page.

Step 3 — Setting Up Tailwind CSS with Laravel

Next, you’ll install and set up Tailwind CSS to build a landing page.

Make sure your Sail environment is up and running, then install Laravel’s front end dependencies with the npm command, which is used to download and manage JavaScript packages :

  • ./vendor/bin/sail npm install
Output
... added 1327 packages, and audited 1328 packages in 20s 99 packages are looking for funding run `npm fund` for details ...

Then, install Tailwind and its dependencies with:

  • ./vendor/bin/sail npm install -D tailwindcss@latest postcss@latest autoprefixer@latest
Output
... added 9 packages, removed 22 packages, changed 7 packages, and audited 1315 packages in 5s 99 packages are looking for funding run `npm fund` for details ...

Next, you’ll need to create a configuration file for Tailwind. To do that, you’ll use npx, which stands for Node package executer and allows you to execute a Node package. The following npx command will generate a new default Tailwind configuration for your application:

  • ./vendor/bin/sail npx tailwindcss init

This will create a new configuration file named tailwind.config.js in your project’s root directory with the following content:

tailwind.config.js
module.exports = {
  purge: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}

Although there are different ways to set up Tailwind within a project, in this guide we’ll configure Tailwind with Laravel Mix and webpack. Both libraries are used to compile and output front end resources.

Open the file webpack.mix.js using your code editor. It will look like this:

mix.js('resources/js/app.js', 'public/js')
    .postCss('resources/css/app.css', 'public/css', [
        //
    ]);

Laravel Mix uses PostCSS to compile CSS resources. Remove the // characters and include the following highlighted line, which will add Tailwind CSS in the list of CSS resources to process:

Remove the // characters and include the following highlighted line, which requires Tailwind as a PostCSS plugin:

webpack.mix.js
  mix.js("resources/js/app.js", "public/js")
    .postCss("resources/css/app.css", "public/css", [
     require("tailwindcss"),
    ]);

Save the file after making this change.

Next, include Tailwind within the application’s main CSS file. Open resources/css/app.css in your code editor and add the following 3 lines to this file:

resources/css/app.css
@tailwind base;
@tailwind components;
@tailwind utilities;

Save when finished.

Next, you’ll need to build the front end assets with NPM:

  • ./vendor/bin/sail npm run dev

You will receive output that is similar to the following, with a line like the the highlighted Compiled Successfully portion that indicates you have integrated all of the components into your Sail environment:

Output
Laravel Mix v6.0.24 ✔ Compiled Successfully in 5515ms ┌───────────────────────────────────────────────────────────────────┬──────────┐ │ File │ Size │ ├───────────────────────────────────────────────────────────────────┼──────────┤ │ /js/app.js │ 597 KiB │ │ css/app.css │ 3.81 MiB │ └───────────────────────────────────────────────────────────────────┴──────────┘ webpack compiled successfully

Tailwind is now configured and you have built the front end assets for your site.. In the next step, you’ll create a new landing page for your application.

Step 4 — Creating a Landing Page

With Tailwind’s configuration in place, you can now start building your application’s front end views. In Laravel, templates are typically stored in the resources/views directory. The page you saw before when opening the application from a browser (http://localhost) is defined in a single template called welcome.blade.php, in that directory.

In your code editor, open a new file called index.blade.php in the resources/views directory.

The following example template defines an “about me” HTML page with a few unstyled elements. It uses an example avatar image but you may replace it with an image of your own.

Create a new img directory in the public application folder:

  • mkdir public/img

Save your preferred image to this new directory, under the name profile_image.png.

In the following example, notice the use of the highlighted {{ asset… }} helper lines to define paths for both the CSS and the image files. This function outputs the correct public path for application resources located in the public directory.

Copy this content to your own index.blade.php:

resources/views/index.blade.php
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Sammy the Shark - About Page</title>
    <meta name="description" content="My Application Description">
    <meta name="author" content="Sammy">
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
<div>
    <img src="{{ asset('img/profile_image.png') }}" width="200" alt="avatar"/>
    <h1>Sammy the Shark</h1>
    <p>Content Creator</p>
    <p>Hello, I'm Sammy. I am a friendly shark interested in Linux, coding, and community.
        You can find out more about me in the following links:</p>
    <div>
        <div><a href="https://twitter.com/digitalocean">Twitter</a></div>
        <div><a href="https://www.linkedin.com/company/digitalocean">LinkedIn</a></div>
        <div><a href="https://instagram.com/thedigitalocean">Instagram</a></div>
    </div>
</div>
</body>
</html>

Save the file when you’re finished editing its contents.

Now edit the routes/web.php file to modify the main route so that it uses the newly created template. Open that file using your code editor, and replace welcome with index to change the view used by the main application endpoint. This is how the updated route declaration will look like once you’re finished:

routes/web.php
Route::get('/', function () {
    return view('index');
});

Save the file. You can now reload the application page in your browser to see the new index page. You’ll see a page like this:
Laravel about me page with tailwind - base template

By default, Tailwind removes all styling from elements, which gives you freedom to build up your views by combining and mixing Tailwind CSS utility classes. In the next section, you’ll learn how to combine some of these utility classes in order to create a responsive “about me” page.

Step 5 — Styling Your Landing Page with Tailwind CSS

Building responsive pages is an important front end development requirement, since users may access your website or application from many different devices, each with different screen sizes.

Tailwind offers selectors that are able to apply styles per screen size. This way, you can create responsive containers by setting up the smallest width as default, and appending the additional responsive sizes for bigger screens. For instance, an element set with class="w-3/4 lg:w-1/2" will set a default width of 3 quarters the width of the parent element, which will be valid for smaller screens, but for larger screens (lg: selector), it will use half the width of the parent element.

Notice that you can combine the responsive selectors with any utility class, not only those associated with an element’s size. You can, for instance, hide an element at a certain breakpoint, change its colors, or even turn it into a grid with a variable number of columns.

You can find all available responsive selectors and their equivalent breaking points at the official Tailwind documentation.

The following template sets up a responsive content area at the center of the page, using background gradients and an example avatar image. For the buttons, it uses a grid flow system that will break the container into three columns starting at medium screens, but will make the buttons occupy the full container size when the page is accessed from smaller screens.

Open the resources/views/index.blade.php file that you created in the previous step in your code editor and replace the contents with the following template:

resources/views/index.blade.php
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Sammy the Shark - About Page</title>
    <meta name="description" content="My Application Description">
    <meta name="author" content="Sammy">
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body class="bg-gradient-to-r from-blue-400 via-purple-600 to-blue-700">

<div class="w-3/4 lg:w-1/2 mx-auto rounded-md bg-gray-200 shadow-lg m-20 p-10 text-center">
    <img src="{{ asset('img/profile_image.png') }}" class="w-32 lg:w-1/6 bg-blue-600 mx-auto rounded-lg mb-4" alt="avatar"/>
    <h1 class="text-3xl">Sammy the Shark</h1>
    <p class="text-gray-500 pb-4">Content Creator</p>
    <p class="text-gray-700 mb-6">Hello, I'm Sammy. I am a friendly shark interested in Linux, coding, and community.
        You can find out more about me in the following links:</p>

    <div class="grid grid-cols-1 md:grid-cols-3 grid-flow-row gap-6">
        <div class="px-4 py-2 bg-blue-600 text-gray-100 rounded-md mr-4 hover:bg-blue-700"><a href="https://twitter.com/digitalocean">Twitter</a></div>
        <div class="px-4 py-2 bg-blue-600 text-gray-100 rounded-md mr-4 hover:bg-blue-700"><a href="https://www.linkedin.com/company/digitalocean">LinkedIn</a></div>
        <div class="px-4 py-2 bg-blue-600 text-gray-100 rounded-md mr-4 hover:bg-blue-700"><a href="https://instagram.com/thedigitalocean">Instagram</a></div>
    </div>

</div>
</body>
</html>

This template will produce the following page:

Final result - Laravel about me page with Tailwind

And this is how the page adapts to different screen sizes:

Laravel Tailwind Responsive About Me Page

In the updated template, each HTML element has a number of Tailwind classes and selectors applied to them. Tailwind uses specific nomenclature for its utility classes to create responsive layouts. Each of the following is used in the example template to create the final result:

  • bg-gradient-to-r: creates a gradient from left to right, using the specified colors.
  • w-1/3: sets the width of the element to one third (1/3) of the parent’s element width. There are many different ways to set up an element’s width within Tailwind.
  • mx-auto: centers the element.
  • rounded-md: creates rounded corners, “medium” (md) in size.
  • shadow-lg: creates a shadow effect, “large” (lg) in size.
  • mr-* and other m variants: used to set up an element’s margins.
  • pb-* and other p variants: used to set up an element’s padding.
  • hover:bg-blue-700: changes the background color of the selected element on mouse hover.

Check Tailwind’s official documentation for a complete reference of all available utility classes.

Conclusion

In this tutorial, you’ve bootstrapped a new Laravel application using Laravel Sail and Tailwind CSS. You also created a responsive “about me” landing page using Tailwind’s powerful utility classes.

If you’d like to build a more complex landing page and learn more about Tailwind in the process, you can follow our guide on How To Build a Styled Landing Page with Tailwind CSS for detailed instructions on how to create a complete website page with this framework.

If you’d like to learn more about Laravel in a project-based guide, you can refer to our How To Build a Links Landing Page in PHP with Laravel series. For more PHP content, check our PHP tag.

Creative Commons License