Paginated responsive image gallery with PHP, MySQL and CSS

Paginated responsive image gallery with PHP, MySQL and CSS. Code with demo and free download.

How to make a paginated responsive image gallery

In this tutorial I will show you how to make a paginated three column responsive image gallery using PHP, MySQL and CSS.

In the demo example and download, there are thirty six images, of which we retrieve the filenames from our database.
The images are kept in our 'images' folder.
We're going to limit the images to twelve per page, which divides nicely into three images per row on screens over 900px wide, two per row for screens under 900px wide and one image per row for screens under 360px wide.

The CSS:

This should go preferably in your style sheet, or else in your document head between the style tags.

First we'll create a containing div for the navigation, with the id 'pagination' and add a 40px margin top and bottom to give some space above and below.

/* The pagination container div: */
#pagination {
margin:40px 0;

Then we need to create the styling for the navigation buttons and create a class to hide the navigation buttons if there's no more than one page.
We also need to create an 'active' class to underline the number on the active page button:

Next we'll create a containing div with the id 'gallery' and add a 40px margin top and bottom to give the gallery space above and below.

/* The gallery container div: */
#gallery {
margin:40px 0;

Then we need to create an image container that can be repeated for each image.

The image container is where we set the responsive percentage width and padding.
The padding sets the spacing between the images.
For the main part of our stylesheet, screens above 900px wide, the width is set at 31.33%, while the image container has a padding of 1%.
For three images in a row, 31.33% each and 1% padding left and right of each, all together it adds up to 99.99%, which rounds up to 100%. Awesome.

To snap our image containers inline, we float them to the left and add the alignment 'left:0':

/* The image container class: */
.img-container {

Now we need to add another container inside the image container with a height and padding of 0, after which we add bottom padding of 100%.
This matches the height to the percentage width, giving us our perfect responsive squares.
Then we 'crop' the image within the container by hiding the overflow:

/* The image container inner container: */
.img {

Next we need to oversize the images and position them using 'transform'.
For this step you can add individual ids or classes to each image to size and position them individually, but this just a 'One size fits all' solution.
You can also use image editing software to crop square thumbnails and use those with 'height:auto' and 'width:100%' instead, leaving out the 'transform' settings.

/* The image itself: */
.img img {

Because the images above are floated left, we need to add a clear fix class before the closing tag of our #gallery container:

.clearfix {

Lastly, using Media Queries we edit the width and padding to achieve one column for screens under 360px wide and two columns for screens between 360px and 900px wide:


/* One column */
@media only screen and (max-width: 360px) {
.img-container {
padding:2% 1%;

/* Two columns */
@media only screen and (min-width: 360px) and (max-width: 900px) {
.img-container {

The MySQL database:

In the demo and download we have a database named 'pagination', with a table named 'images' set up as follows:

  1. Name: id | type: INT | length: 2 | Auto_Increment
  2. Name: file | type: VARCHAR | length: 9
Paginated responsive image gallery with php and mysql - database table settings


Include this in the head section of your index.php file:

<meta name="viewport" content="width=device-width, initial-scale=1.0">

The PHP:

First we create a file named 'dbcon.php' and save it in a folder called 'dbcon':


$host = 'localhost'; // Host name
$username = 'root'; // Username
$password = ''; // Password - usually empty for localhost server
$database = 'pagination'; // Name of the database containing our 'images' table

// Let's call our database connection variable $dbCon:

$dbCon = mysqli_connect($host, $username, $password, $database);

// Check connection
if (!$dbCon) {// If the database connection fails...
die('Connection failed: ' . mysqli_connect_error());// ... kill the connection and say 'Connection failed: ' followed by the error.

I'll split this into the three main parts, starting with including the database connection file and the calculations:

include_once('dbcon/dbcon.php');// Include the database connection that we created

$per_page = 12;// Number of images per page, change for a different number of images per page

// Get the page and offset value:
if (isset($_GET['page'])) {
$page = $_GET['page'] - 1;
$offset = $page * $per_page;
// Otherwise we render the page and offset as non-existent:
else { $page = 0;
$offset = 0;

// Count the total number of images in the table ordering by their id's ascending:
$images = "SELECT count(id) FROM images ORDER by id ASC";
$result = mysqli_query($dbCon, $images);
$row = mysqli_fetch_array($result);
$total_images = $row[0];

// Calculate the number of pages:
if ($total_images > $per_page) {//If there is more than one page
$pages_total = ceil($total_images / $per_page);
$page_up = $page + 2;
$page_down = $page;
$display ='';//leave the display variable empty so it doesn't hide anything
else {// Else if there is only one page
$pages = 1;
$pages_total = 1;
$display = ' class="display-none"';//class to hide page count and buttons if only one page

Next we set up and display the 'page number out of how many pages' heading and the navigation buttons:


echo '<h2'.$display.'>Page '; echo $page + 1 .' of '.$pages_total.'</h2>';// Page out of total pages

$i = 1;// Set the $i counting variable to 1

echo '<div id="pageNav"'.$display.'>';// our $display variable will do nothing if more than one page

// Show the page buttons:
if ($page) {
echo '<a href="index.php"><button><<</button></a>';// Button for first page [<<]
echo '<a href="index.php?page='.$page_down.'"><button><</button></a>';// Button for previous page [<]

for ($i=1;$i<=$pages_total;$i++) {
if(($i==$page+1)) {
echo '<a href="index.php?page='.$i.'"><button class="active">'.$i.'</button></a>';// Button for active page, underlined using 'active' class

// In this next if statement, calculate how many buttons you'd like to show. You can remove to show only the active button and first, prev, next and last buttons:
if(($i!=$page+1)&&($i<=$page+3)&&($i>=$page-1)) {// This is set for two below and two above the current page
echo '<a href="index.php?page='.$i.'"><button>'.$i.'</button></a>'; }

if (($page + 1) != $pages_total) {
echo '<a href="index.php?page='.$page_up.'"><button>></button></a>';// Button for next page [>]
echo '<a href="index.php?page='.$pages_total.'"><button>>></button></a>';// Button for last page [>>]
echo '</div>';// #pageNav end

echo '<div id="gallery">';// #gallery div to contain the gallery

Finally, we select our data from the table and loop the array through the 'while' loop:

// Select the images from the table limited as per our $offset and $per_page total:

$result = mysqli_query($dbCon, "SELECT * FROM images ORDER by id ASC LIMIT $offset, $per_page");
while($row = mysqli_fetch_array($result)) {// Open the while array loop

// Define the image variable by retrieving the filename from the table:

// Then we echo our HTML for each image:
echo '<div class="img-container">';
echo '<div class="img">';

echo '<a href="images/'.$image.'">';
echo '<img src="images/'.$image.'">';
echo '</a>';

echo '</div>';// .img end
echo '</div>';// .img-container end

}// Close the while array loop

echo '</div>';// #gallery end

echo '<div class="clearfix"></div>';// The clearfix