email-templates Images are shown in preview but not in Gmail - javascript

I'm using email-template package for sending styled emails. Everything seems to work fine in preview of email (preview option is given in package itself. it renders sent email preview in tab if placed true). but when I get email in my gmail account images are not visible. I can tell that paths / images in the setting / code exists because in preview everything is placed just right.
smtpTransport = nodemailer.createTransport(
smtpTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
jsonTransport: true,
auth: {
user: 'sender.example#gmail.com',
pass: '123123',
},
})
);
smtpTransport.use('compile', base64ToS3());
const templateWrapper = new Email({
transport: smtpTransport,
send: true,
preview: true,
views: {
options: {
extension: 'ejs',
},
root: path.join(__dirname, 'email/html/events'),
},
juice: true,
juiceSettings: {
tableElements: ['TABLE'],
},
juiceResources: {
preserveImportant: true,
webResources: {
relativeTo: path.join(__dirname, 'email/assets'),
images: true,
},
},
});
Here is my HTML template:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Efys - Welcome</title>
<style>
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: border-box;
}
body {
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 0.8rem;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
.bg-brand-color-blue-dark {
background-color: #033e75;
}
.bg-brand-color-gold-light {
background-color: #f0ede6;
}
.bg-brand-color-gold-dark {
background-color: #d0a345;
}
.bg-white {
background-color: #ffffff;
}
.brand-color-gold-dark {
color: #d0a345;
}
.brand-color-gold-light {
color: #f0ede6;
}
.brand-color-blue-dark {
color: #033e75;
}
.text-color-white {
color: #ffffff;
}
.text-color-black {
color: #000000;
}
.display-block {
display: block;
}
.margin-top-0rem {
margin-top: 0;
}
.margin-top-1rem {
margin-top: 1rem;
}
.margin-top-2rem {
margin-top: 2rem;
}
.margin-bottom-2rem {
margin-bottom: 2rem;
}
.padding-full-1rem {
padding: 1rem;
}
.padding-full-2rem {
padding: 2rem;
}
.padding-top-2rem {
padding-top: 2rem;
}
.padding-bottom-5rem {
padding-top: 5rem;
}
.border-solid-black {
border: 1px solid #000000;
}
.border-radius-half {
border-radius: 0.5rem;
}
.border-radius-1rem {
border-radius: 1rem;
}
.whitespace {
white-space: normal;
}
.font-size-x1 {
font-size: 1rem;
}
.font-size-x2 {
font-size: 2rem;
}
a,
a:visited {
color: blue;
}
.text-decoration-none {
text-decoration: none;
}
ol {
padding-left: 15px;
}
p {
margin-top: 1rem;
margin-bottom: 0;
}
.strong {
font-weight: bold;
}
h3 {
margin-bottom: 0;
}
h3 + p {
margin-top: 0;
}
.inline-icon {
margin-right: 5px;
}
.flexbox {
display: flex;
}
.flex-row {
flex-direction: row;
}
.flex-nowrap {
flex-wrap: nowrap;
}
.flexbox .cell {
width: 50%;
}
.flexbox .cell:nth-child(2) {
text-align: right;
}
.maximum-width {
width: 100%;
max-width: 36.25rem;
margin: 0 auto;
}
.logo {
width: 100%;
max-width: 36.25rem;
margin: 0 auto;
}
.logo img {
border: 0 none;
outline: 0 none;
width: 100%;
height: auto;
}
#media only screen and (max-width: 480px) {
.footer > .flexbox .cell {
width: 100%;
text-align: center;
}
.footer > .flexbox .cell:nth-child(2) {
text-align: center;
margin-top: 1rem;
}
.footer > .flex-nowrap {
flex-wrap: wrap;
}
.inner-cell.flexbox {
display: block;
max-width: 100%;
margin: 0 auto;
}
}
</style>
</head>
<body>
<div
class="wrapper display-block bg-brand-color-blue-dark padding-full-1rem"
>
<!-- logo -->
<div class="logo display-block" style="margin: 0 auto;">
<img
class="display-block"
src="efy-registration-header.jpg"
alt="abc def"
style="border-top-left-radius: 1rem; border-top-right-radius: 1rem;"
/>
</div>
<!-- content -->
<div
class="content display-block maximum-width bg-white text-color-black padding-full-2rem"
style="border-bottom-left-radius: 1rem; border-bottom-right-radius: 1rem;"
>
<p class="strong">Dear <%= clientName %>,</p>
<p>
You have successfully registered for <%= efyTitle %> on <%= efyDay %> at <%= startTime %>
</p>
<p>Your Reference ID is: <%= referenceId %></p>
<% if (displayAddress) { %>
<p>Zoom link: <%= address %></p>
<% } else { %>
<p>
Zoom link: You should receive an email update with the link to the
live efy
</p>
<% } %>
<h3>Zoom Instructions</h3>
<p>To join a Zoom meeting on a computer or mobile device:</p>
<ol>
<li>
Download the Zoom app from their Download Center
<a href="https://zoom.us/download" target="_blank"
>https://zoom.us/download</a
>. Otherwise, you will be prompted to download and install Zoom when
you click a join link.
</li>
</ol>
</div>
<!-- footer -->
<div
class="footer maximum-width text-color-white"
style="margin: 1rem auto 5rem;"
>
<div
class="flexbox flex-row flex-nowrap"
style="justify-content: center; align-items: flex-end;"
>
<div class="cell">
<div class="flexbox flex-row flex-nowrap inner-cell">
<div class="col" style="margin-right: 0.5em;">
<img
src="logo_icon.png"
alt="abc def"
width="50"
height="auto"
/>
</div>
<div class="col">
Villa 1, Alwasl Rd. <br />
Alsafa 2 <br />
Dubai, United Arab Emirates
</div>
</div>
<p>
<span class="strong brand-color-gold-dark">T.</span>
<a
href="tel:+97143809298"
class="text-decoration-none strong"
style="color: #FFFFFF;"
>+971 (0)4 380 9296</a
>
</p>
<p class="margin-top-0rem">
<span class="strong brand-color-gold-dark">E.</span>
<a
href="mailto:info#example.com"
class="text-decoration-none strong"
style="color: #FFFFFF;"
>info#example.com</a
>
</p>
</div>
<div class="cell">
<p>
<span class="inline-icon"
><a href="#"
><img
src="icon-facebook.png"
width="40"
height="auto"/></a
></span>
<span class="inline-icon"
><a href="#"
><img
src="icon-twitter.png"
width="40"
height="auto"/></a
></span>
<span class="inline-icon"
><a href="#"
><img
src="icon-instagram.png"
width="40"
height="auto"/></a
></span>
<span class="inline-icon"
><a href="#"
><img
src="icon-linkedin.png"
width="40"
height="auto"/></a
></span>
</p>
<p class="brand-color-gold-dark strong">#example.com</p>
<p class="margin-top-0rem">
<span class="strong brand-color-gold-dark">W.</span>
<a
href="//example.com"
class="text-decoration-none strong"
style="color: #FFFFFF;"
>example.com</a
>
</p>
</div>
</div>
</div>
</div>
</body>
</html>

When you load an HTML page and use the image like below
<img
src="icon-linkedin.png"
width="40"
height="auto"
/>
It actually tells the browser that, load the image from the same directory from where you loaded the HTML page.
Here comes the problem. When your email is loaded in the Gmail it will also tell browser the same and the browser will not be able to locate the image.
Solution:
If you are sending it from the backend. Then upload the image in any public url. You can upload the image in you frontend hosting and find the link. Then use the link directly. Your image need to be accessible publicly.
If you do not have any other option or hosting. Upload the image in any public github/gitlab repo and use the link.

According to the docs for nodemailer-base64-to-s3, you need to pass in some configuration options to the base64ToS3 method. It says the aws/params/Bucket is required.
I believe the following should give you a good start:
smtpTransport.use('compile', base64ToS3({
aws: {
params: {
Bucket: "bucket_name_here"
}
}
}));
See https://github.com/forwardemail/nodemailer-base64-to-s3/blob/master/example.js for another example.

Related

Why can't I use the search features in html and javascript?

I'm trying to create a website about song lyrics using the Musixmatch API and want to apply a custom element, shadow DOM, webpack, etc.
but I have a problem in the search function because it can't search even though I already created the function in src -> script -> data -> data-source.js and songs.js
I beg for your help, thank you :)
and it still undefined result :(
index.html
document.addEventListener("DOMContentLoaded", main);
/* Dasar */
* {
margin: 0;
padding: 0;
font-family: 'Montserrat', sans-serif;
}
:root {
--warna-hitam:#333333;
--warna-ungu: #2c072c;
--warna-pink: #ff536e;
--warna-putih: #FFFAF0;
--gradasi: linear-gradient(120deg, #fccb90 0%, #d57eeb 100%);
--bayangan: rgba(0, 0, 0, 0.2);
}
h1,h2,h3{
font-family: 'Montserrat', sans-serif;
text-align: center;
}
h4,h5,h6,p {
font-family: 'Poppins', sans-serif;
}
.section {
padding: 4rem 1.5rem;
display: block;
}
body,
button,
input,
select,
textarea{
font-family: 'Montserrat', sans-serif;
}
.container {
text-align: center;
margin: 0;
}
/* ----------------------------------- */
/*Form Pencarian*/
form {
width:1200px;
margin:50px auto;
}
.search {
padding:20px 30px;
border-radius: 15px;
background:rgba(197, 190, 190, 0.2);
border:0px solid #dbdbdb;
font-family: 'Montserrat', sans-serif;
font-size: 16px;
}
.button {
position:relative;
padding:18px 24px;
border-radius: 12px;
margin-left: 10px;
left:-8px;
background-color:#FF8C00;
color:#fafafa;
font-family: 'Montserrat', sans-serif;
font-weight: bolder;
font-size: 18px;
}
.button:hover {
background-color:#fafafa;
color:#FF8C00;
}
/* ----------------------------------- */
/* Card */
.cards-list {
z-index: 0;
width: 100%;
display: flex;
justify-content: space-around;
flex-wrap: wrap;
}
.card {
margin: 30px auto;
width: 300px;
height: 300px;
border-radius: 40px;
box-shadow: 5px 5px 30px 7px rgba(0,0,0,0.25), -5px -5px 30px 7px rgba(0,0,0,0.22);
cursor: pointer;
transition: 0.4s;
}
.card .card_image {
width: inherit;
height: inherit;
border-radius: 40px;
}
.card .card_image img {
width: inherit;
height: inherit;
border-radius: 40px;
object-fit: cover;
}
.card .card_title {
text-align: center;
border-radius: 0px 0px 40px 40px;
font-family: sans-serif;
font-weight: bold;
font-size: 30px;
margin-top: -80px;
height: 40px;
}
.card:hover {
transform: scale(0.9, 0.9);
box-shadow: 5px 5px 30px 15px rgba(0,0,0,0.25),
-5px -5px 30px 15px rgba(0,0,0,0.22);
}
.title-white {
color: white;
}
.title-black {
color: black;
}
#media all and (max-width: 500px) {
.card-list {
/* On small screens, we are no longer using row direction but column */
flex-direction: column;
}
}
/* ----------------------------------- */
/* Menu Navigasi */
ul.topnav {
list-style-type: none;
margin: 0;
padding: 0;
box-shadow: rgba(0, 0, 0, 0.2);
overflow: hidden;
background-color: var(--warna-ungu);
}
ul.topnav li {
float: left;
}
ul.topnav li a {
display: inline-block;
color: #f2f2f2;
text-align: center;
padding: 14px 16px;
text-decoration: none;
transition: 0.3s;
font-size: 17px;
}
ul.topnav li a:hover {
background-color: #111;
}
ul.topnav li.icon {
display: none;
}
/* ----------------------------------- */
/* Text Heading */
.heading {
margin: 20px;
font-size: 2rem ;
color: var(--warna-pink);
}
.subtitle {
margin: 15px;
text-align: center;
font-size: 1.2rem;
color: #3f4957;
}
/* ----------------------------------- */
/* FONT */
#import url('https://fonts.googleapis.com/css?family=Montserrat&display=swap');
#import url('https://fonts.googleapis.com/css?family=Poppins&display=swap');
/* ----------------------------------- */
/* Footer */
footer{
display: flex;
flex-direction: column;
margin: 20px 0px;
padding: 30px 30px;
background-color: var(---warna-putih);
color: #3f4957;
text-align: center;
font-size: 12px;
font-weight: 800;
}
/* ----------------------------------- */
/* RENSPONSIVE */
/* Saat lebar layar kurang dari 680 pixel, sembunyikan semua menu item kecuali item yang pertama yaitu("Home"). Tampilkan juga list item yang berisi link untuk membuka menu yaitu (li.icon) */
#media screen and (max-width:680px) {
ul.topnav li:not(:first-child) {
display: none;
}
ul.topnav li.icon {
float: right;
display: inline-block;
}
}
/* Class dengan nama "responsive" akan ditambahkan oleh JavaScript saat user mengklik icon. Munculnya Class ini akan mendisplay isi list menu
*/
#media screen and (max-width:680px) {
ul.topnav.responsive {position: relative;}
ul.topnav.responsive li.icon {
position: absolute;
right: 0;
top: 0;
}
ul.topnav.responsive li {
float: none;
display: inline;
}
ul.topnav.responsive li a {
display: block;
text-align: left;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="src/style/style.css">
<script src="https://kit.fontawesome.com/1cb0b252aa.js" crossorigin="anonymous"></script>
<link rel="shortcut icon" href="src/img/favicon.png">
<title>DapatLirik</title>
</head>
<header>
<nav id="appBar" class="app-bar">
<ul class="topnav">
<li><i class="fas fa-music"></i>Dapat<strong>Lirik</strong></li>
<li>About Us</li>
<li>Find Lyrics</li>
<li class="icon">
☰
</li>
</ul>
</nav>
</header>
<body>
<main>
<!-- Search Lagu -->
<section>
<h3 class="heading" id="find-lyrics" ><span><i class="fab fa-mixcloud fa-2x"></i></span> Lirik Favorit Anda Disini!</h3>
<p class="subtitle">Temukan Lirik Lagu favorit anda dengan satu klik saja!</p>
<div class="container search-container" id="search-container">
<form id="track.search">
<input class="search" type="search" placeholder="Ketik Judul Lagu/Lirik" id="searchElement" required>
<input class="button" type="button" id="searchButtonElement" value="Cari">
</form>
</div>
</section>
<!-- Top 8 Tracks -->
<section>
<h3 class="heading"><span><i class="fas fa-microphone-alt fa-2x"></i></span>Top 8 Lirik Terfavorit</h3>
<p class="subtitle">8 Lirik Lagu Terfavorit Akhir-Akhir Ini</p>
<div id="songList"></div>
</section>
<!-- Card -->
<div class="cards-list" id="songList">
<div class="card 1" id="artist.albums.get">
<div class="card_image"> <img src="https://i.redd.it/b3esnz5ra34y.jpg" /> </div>
<div class="card_title title-white">
<p>Card Title</p>
</div>
</div>
<div class="card 2">
<div class="card_image" id="artist.albums.get">
<img src="https://cdn.blackmilkclothing.com/media/wysiwyg/Wallpapers/PhoneWallpapers_FloralCoral.jpg" />
</div>
<div class="card_title title-white">
<p>Card Title</p>
</div>
</div>
<div class="card 3">
<div class="card_image" id="artist.albums.get">
<img src="https://media.giphy.com/media/10SvWCbt1ytWCc/giphy.gif" />
</div>
<div class="card_title">
<p>Card Title</p>
</div>
</div>
<div class="card 4">
<div class="card_image" id="artist.albums.get">
<img src="https://media.giphy.com/media/LwIyvaNcnzsD6/giphy.gif" />
</div>
<div class="card_title title-black">
<p>Card Title</p>
</div>
</div>
<div class="card 5">
<div class="card_image" id="artist.albums.get"> <img src="https://i.redd.it/b3esnz5ra34y.jpg" /> </div>
<div class="card_title title-white">
<p>Card Title</p>
</div>
</div>
<div class="card 6">
<div class="card_image" id="artist.albums.get">
<img src="https://cdn.blackmilkclothing.com/media/wysiwyg/Wallpapers/PhoneWallpapers_FloralCoral.jpg" />
</div>
<div class="card_title title-white">
<p>Card Title</p>
</div>
</div>
<div class="card 7">
<div class="card_image" id="artist.albums.get">
<img src="https://media.giphy.com/media/10SvWCbt1ytWCc/giphy.gif" />
</div>
<div class="card_title">
<p>Card Title</p>
</div>
</div>
<div class="card 8">
<div class="card_image" id="artist.albums.get">
<img src="https://media.giphy.com/media/LwIyvaNcnzsD6/giphy.gif" />
</div>
<div class="card_title title-black">
<p>Card Title</p>
</div>
</div>
</div>
</main>
<!-- Javascript Disini -->
<script>
const myMenu = () => {
document.getElementsByClassName("topnav")[0].classList.toggle("responsive");
}
</script>
<script src="src/script/data/songs.js"></script>
<script src="src/script/data/data-source.js"></script>
<script src="src/script/view/main.js"></script>
<script src="app.js"></script>
</body>
<footer>
<h3><i class="fas fa-music"></i>Dapat<strong>Lirik</strong> 2020 - By <span><i class="fab fa-instagram"></i></span>Ihsandroid </h3>
</footer>
</html>
//data-source.js
function DataSource(onSuccess, onFailed) {
this.onSuccess = onSuccess;
this.onFailed = onFailed;
}
DataSource.prototype.searchSongs = function (keyword) {
const filteredSongs = songs.filter(songs => songs.name.toUpperCase().includes(keyword.toUpperCase()));
if (filteredSongs.length) {
this.onSuccess(filteredSongs);
} else {
this.onFailed(`${keyword} is not found`);
}
};
//songs.js
const songs = [
{
"track_id": 15445219,
"track_name": "Alejandro",
"has_lyrics": 1,
"album_name": "The Fame Monster",
"artist_id": 378462,
"artist_name": "Lady Gaga",
"updated_time": "2017-01-08T07:30:05Z"
},
{
"track_id": 15445219,
"track_name": "Alejandro",
"has_lyrics": 1,
"album_name": "The Fame Monster",
"artist_id": 378462,
"artist_name": "Lady Gaga",
"updated_time": "2017-01-08T07:30:05Z"
},
{
"track_id": 15445219,
"track_name": "Alejandro",
"has_lyrics": 1,
"album_name": "The Fame Monster",
"artist_id": 378462,
"artist_name": "Lady Gaga",
"updated_time": "2017-01-08T07:30:05Z"
}
]
main.js
const main = () => {
const searchElement = document.querySelector("#searchElement");
const buttonSearchElement = document.querySelector("#searchButtonElement");
const songsListElement = document.querySelector("#songList");
const onButtonSearchClicked = () => {
const dataSource = new DataSource(renderResult, fallbackResult);
dataSource.searchSongs(searchElement.value);
};
const renderResult = results => {
songsListElement.innerHTML = "";
results.forEach(songs => {
const {name, album, description} = songs
const songsElement = document.createElement("div");
songsElement.setAttribute("class", "songs");
songsElement.innerHTML = `<img class="songs-album" src="' + ${album} + '" alt="Songs Album">
<div class="songs-info">
<h2>${name}</h2>
<p>${description}</p>
</div>`;
songsListElement.appendChild(songsElement);
})
};
const fallbackResult = message => {
songsListElement.innerHTML = "";
songsListElement.innerHTML += `<h2 class="placeholder">${message}</h2>`;
};
buttonSearchElement.addEventListener("click", onButtonSearchClicked);
};
This is My Code on GITHUB :
CLICK HERE
You are calling toUpperCase() on song.name, which is a field that doesn't exist on objects in songs. Did you mean songs.track_name?
I see two issues here. 1) name field is not the part of song object/json in the songs arrays (songs.js) file. Either change the field name to one of the keys on which you want to search(track_name , album_name etc)
if you want to search on name it should be
songs.filter(songs => songs.track_name.toUpperCase().includes(keyword.toUpperCase()));
2) You are using name, album, description fields in renderResult function.
change them to track_name,album_name etc.
const renderResult = (results) => {
songsListElement.innerHTML = '';
results.forEach((songs) => {
const { track_name, album_name, updated_time } = songs;
const songsElement = document.createElement('div');
songsElement.setAttribute('class', 'songs');
songsElement.innerHTML = `<img class="songs-album" src="' + ${album_name} + '" alt="Songs Album">
<div class="songs-info">
<h2>${track_name}</h2>
<p>${updated_time}</p>
</div>`;
songsListElement.appendChild(songsElement);
});
After this I see you are trying to load some images as well. You need to put images with the name of the songs to load it from local

Content of horizontal scroll div is cut

I am inserting into my HTML using javascript. My code is being truncated/ cut off.
Here's my code:
function feedbackDiv(feedback_id, feedback_title, feedback_content, feedback_author) {
return querySnapshot.forEach(function(doc) {
const data = doc.data();
var feedback_title = data.title;
var feedback_content = data.content;
var feedback_author = data.author;
document.getElementById("küchen_feedback_p").insertAdjacentHTML('beforeend', feedbackDiv(doc.id, feedback_title, feedback_content, feedback_author));
});
};
.küchen_co {
padding: 20px;
}
.küchen_feedback_p {
overflow-x: auto;
}
.feedback_container {
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
background-color: #212121;
color: #ffffff;
text-align: center;
}
.feedback_container:hover {
border: 1px solid #7ef6a9;
animation: color_change 1s;
background-color: #7ef6a9;
color: #212121;
}
<div class="küchen_co center">
<div class="küchen_feedback_p center" id="küchen_feedback_p" style="display: none;">
</div>
<div class="noDataContainer_kfeedback_p" id="noDataContainer_kfeedback_p" style="text-align:center;">
<img src="./broken_heart.png" width="80px" height="auto" />
<p class="nothing_found_k küchenH">Es wurden derzeit keine Feedbacks abgesendet.</p>
</div>
</div>
<div class="feedback_container" id="feedbackDiv" style="width:300px; height: 250px; margin-right: 20px;">
<p id="feedback_id" style="display: none;">${feedback_id}</p>
<h1 class="" style="word-wrap: break-word;">${feedback_title}</h1>
<p class="" style="word-wrap: break-word;">${feedback_content}</p>
<p class="" id="feedback_author" style="display: none;">${feedback_author}</p>
</div>
But the content of the scrolling div is cutted: https://www.dropbox.com/s/8f95tjojkbpku35/scroll.PNG?dl=0
~filip
For all with further issues. The problem might be the following lines of code:
justify-content: center;
align-items:center;
text-align:center;

Button positioning in completely wrong place to where it should

I've got a webpage with 2 different sections. Each are the height of the viewport. One has a button 'work' in the center. When this is clicked, that disappears and some links appear where it was. The same sort of thing applies for the next section.
I'm trying to add a reset function to remove the links and add the buttons back. I originally tried to make one button reset all sections but, after that didn't work, I'm now trying to make an individual button for each section.
I've done this but my problem is that the second section's reset button appears in the same place as the first section's one. Both should appear at the bottom right section of their respective sections.
function openSites(categoryType) {
if (categoryType == "work") {
var sites = document.getElementById("workSites");
var button = document.getElementById("workButton");
} else if (categoryType == "other") {
var sites = document.getElementById("otherSites");
var button = document.getElementById("otherButton");
}
sites.classList.add("show");
sites.classList.remove("hide");
button.classList.add("hide");
}
function reset(categoryType) {
if (categoryType == "work") {
var sites = document.getElementById("workSites");
var button = document.getElementById("workButton");
} else if (categoryType == "other") {
var sites = document.getElementById("otherSites");
var button = document.getElementById("otherButton");
}
sites.classList.remove("show");
sites.classList.add("hide");
button.classList.remove("hide");
}
function betterReset() {
for (category in document.getElementsByClassName("category-container")) {
document.write(category);
}
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.page {
display: inline-block;
overflow: hidden;
width: 100%;
height: 100vh;
}
#page-1 {
display: block;
background-color: #3faae4;
}
#page-2 {
display: block;
background-color: #ffffff;
}
.pointer {
cursor: pointer;
}
#work {
height: 100%;
width: 100%;
}
#other {
height: 100%;
width: 100%;
}
#workSites {
height: 100%;
width: 100%;
}
#otherSites {
height: 100%;
width: 100%;
}
.sites {
list-style-type: none;
height: 100%;
}
.site {
padding: 50px 0px;
flex-grow: 1;
text-align: center;
}
.center {
display: flex;
align-items: center;
justify-content: center;
}
.category-container {
height: 100%;
}
.category-button {
border: solid 0.5px;
padding: 60px;
}
.buttonClose {
position: absolute;
border: solid 0.5px;
border-radius: 5px;
right: 3px;
bottom: 0px;
width: 70px;
height: 35px;
}
.show {
display: block;
}
.hide {
display: none;
}
<!DOCTYPE html>
<html>
<head>
<title>Nick's site</title>
<link rel="stylesheet" type="text/css" href="./styles3.css">
<meta name="viewport" content="width= device-width, inital-scale=1">
</head>
<body>
<div id="page-1" class="page">
<div id="work">
<div id="workButton" class="category-container center">
<a class="category-button pointer" onclick="openSites('work')">Work</a>
</div>
<div id="workSites" class="hide">
<ul class="sites center">
<li class="site"><a class="pointer" href="#">Printfactory</a></li>
<li class="site"><a class="pointer" href="#">Henry's Site</a></li>
</ul>
<button onclick="reset('work')" class="buttonClose pointer" style="z-index: 2;">
Reset
</button>
</div>
</div>
</div>
<div id="page-2" class="page">
<div id="other">
<div id="otherButton" class="category-container center">
<a class="category-button pointer" onclick="openSites('other')">Other</a>
</div>
<div id="otherSites" class="hide">
<ul class="sites center">
<li class="site"><a class="pointer" href="#">#</a></li>
<li class="site"><a class="pointer" href="#">#</a></li>
<li class="site"><a class="pointer" href="#">#</a></li>
</ul>
<button onclick="reset('other')" class="buttonClose pointer" style="z-index: 2;">
Reset2
</button>
</div>
</div>
</div>
</body>
</html>
You are giving a position:absolute tu your reset buttons. This make them take the values of right and bottom relative to next parent with position:relative.In this case being the body tag.
To fix this, add position:relative to your parent divs.
#workSites,
#otherSites {
position: relative;
}
Hope this helps :>
function openSites(categoryType) {
if (categoryType == "work") {
var sites = document.getElementById("workSites");
var button = document.getElementById("workButton");
} else if (categoryType == "other") {
var sites = document.getElementById("otherSites");
var button = document.getElementById("otherButton");
}
sites.classList.add("show");
sites.classList.remove("hide");
button.classList.add("hide");
}
function reset(categoryType) {
if (categoryType == "work") {
var sites = document.getElementById("workSites");
var button = document.getElementById("workButton");
} else if (categoryType == "other") {
var sites = document.getElementById("otherSites");
var button = document.getElementById("otherButton");
}
sites.classList.remove("show");
sites.classList.add("hide");
button.classList.remove("hide");
}
function betterReset() {
for (category in document.getElementsByClassName("category-container")){
document.write(category);
}
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.page {
display: inline-block;
overflow: hidden;
width: 100%;
height: 100vh;
}
#page-1 {
display: block;
background-color: #3faae4;
}
#page-2 {
display: block;
background-color: #ffffff;
}
.pointer {
cursor: pointer;
}
#work {
height: 100%;
width: 100%;
}
#other {
height: 100%;
width: 100%;
}
#workSites {
height: 100%;
width: 100%;
}
#otherSites {
height: 100%;
width: 100%;
}
.sites {
list-style-type: none;
height: 100%;
}
.site {
padding: 50px 0px;
flex-grow: 1;
text-align: center;
}
.center {
display: flex;
align-items: center;
justify-content: center;
}
.category-container {
height: 100%;
}
.category-button {
border: solid 0.5px;
padding: 60px;
}
.buttonClose {
position: absolute;
border: solid 0.5px;
border-radius: 5px;
right: 3px;
bottom: 0px;
width: 70px;
height: 35px;
}
.show {
display: block;
}
.hide {
display: none;
}
#workSites,
#otherSites {
position: relative;
}
<!DOCTYPE html>
<html>
<head>
<title>Nick's site</title>
<link rel="stylesheet" type="text/css" href="./styles3.css">
<meta name="viewport" content="width= device-width, inital-scale=1">
</head>
<body>
<div id="page-1" class="page">
<div id="work">
<div id="workButton" class="category-container center">
<a class="category-button pointer" onclick="openSites('work')">Work</a>
</div>
<div id="workSites" class="hide">
<ul class="sites center">
<li class="site"><a class="pointer" href="#">Printfactory</a></li>
<li class="site"><a class="pointer" href="#">Henry's Site</a></li>
</ul>
<button onclick="reset('work')" class="buttonClose pointer" style="z-index: 2;">
Reset
</button>
</div>
</div>
</div>
<div id="page-2" class="page">
<div id="other">
<div id="otherButton" class="category-container center">
<a class="category-button pointer" onclick="openSites('other')">Other</a>
</div>
<div id="otherSites" class="hide">
<ul class="sites center">
<li class="site"><a class="pointer" href="#">#</a></li>
<li class="site"><a class="pointer" href="#">#</a></li>
<li class="site"><a class="pointer" href="#">#</a></li>
</ul>
<button onclick="reset('other')" class="buttonClose pointer" style="z-index: 2;">
Reset2
</button>
</div>
</div>
</div>
</body>
</html>

How do I maintain my menu, and footer in the same place while horizontal scrolling?

edit/update
I have updated my code and fixed some errors. Now I am trying to fix my footer to stay at the bottom, my menu will not center, and I am trying to have the gallery between header and footer without being clipped by the header. Everything was working until I added the horizontal scroll gallery.
I am trying to achieve the layout:
header top
menu in a line
content/horizontal scroll gallery middle
footer/social icons bottom
Please help
codepen link
/**********************************
General
**********************************/
body {
font-family: 'Roboto', sans-serif;
}
#wrapper {
max-width: 940px;
margin: 0 auto;
padding: 0 5%;
}
a {
text-decoration:none;
}
/**********************************
Heading
**********************************/
header {
float: left;
margin: 0 0 30px 0;
padding: 5px 0 0 0;
width: 100%;
height: 150px;
position:fixed;
}
#logo {
text-align: center;
margin: 0;
}
h1 {
font-family: 'Passion One', cursive;
margin: 15px 0;
font-size: 5em;
font-weight: normal;
line-height: 0.8em;
}
h2 {
font-family: 'Comfortaa', cursive;
font-size: em;
margin: -5px 0 0;
font-weight: normal;
}
/**********************************
Navigatoin
**********************************/
nav {
text-align: center;
padding: 10px 0;
margin: 20px 0 0;
position: fixed;
}
nav ul {
list-style: none;
margin: 0 10px;
padding: 0;
}
nav li {
display: inline-block;
}
nav a {
font-weight: 800;
padding: 15px 10px;
}
/**********************************
Body
**********************************/
#content {
height: 100%;
margin: 0 0 0 0;
top: 0;
}
/**********************************
Footer
**********************************/
footer {
font-size: 0.75em;
text-align: center;
clear: both;
padding-top: 50px;
color: #ccc;
position: fixed;
}
.social-icon {
width: 20px;
height: 20px;
margin: 0 5px;
}
.fttext {
text-align: center;
}
/**********************************
Colors
**********************************/
/* site body */
body {
background-color: #C9BD7C;
color: #5B0123;
}
/* green header */
header{
background: #5B0123;
border-color: #5B0123;
}
/* nav background on mobile devices */
nav {
background: #B41C42;
}
/* logo text */
h1, h2 {
color: #fff;
}
/* links */
a {
color: #C86347;
}
/* nav link */
nav a, nav a:visited {
color: #fff;
}
/* selected nav link */
nav a.selected, nav a:hover {
color: #F8D295;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css">
<link href="https://fonts.googleapis.com/css?family=Comfortaa|Passion+One|Roboto:400,500" rel="stylesheet">
</head>
<!-- content goes here-->
<body>
<header>
<a href="index.html" id="logo">
<h1>Natalie Davis</h1>
<h2>Designer</h2>
</a>
<nav>
<ul>
<li>Portfolio</li>
<li>Resume</li>
<li>Contact</li>
</ul>
</nav>
</header>
<div id="wrapper">
<section id="content">
<div id="img-container">
<div class="picture_holder" style="width: 573px;">
<div class="picture" style="width: 543px;">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Liliumbulbiferumflowertop.jpg/220px-Liliumbulbiferumflowertop.jpg" width="543" height="600" alt="">
<div class="captioning">
<div class="title">link - Test caption and link</div>
<div class="caption">stuff </div>
</div>
</div>
</div>
<div class="picture_holder" style="width: 1124px;">
<div class="picture" style="width: 1094px;">
<img src="https://static.pexels.com/photos/54630/japanese-cherry-trees-flowers-spring-japanese-flowering-cherry-54630.jpeg" width="1094" height="600" alt="">
<div class="captioning">
<div class="caption"><i>CAPTION</i></div>
</div>
</div>
</div>
<div class="picture_holder" style="width: 382px;">
<div class="picture" style="width: 352px;">
<img src="http://www.tonyandsonsnurseries.com.au/images/Plants/Frangipani/FruitSaladLarge.jpg" width="352" height="600" alt="">
<div class="captioning">
<div class="caption"><i>CAPTION</i></div>
</div>
</div>
</div>
<div class="picture_holder" style="width: 439px;">
<div class="picture" style="width: 409px;">
<img src="http://www.beautifulflowerpictures.com/blog/wp-content/uploads/2008/10/beauty_berry_issai_31.jpg" width="409" height="600" alt="">
<div class="captioning"></div>
</div>
</div>
<div class="picture_holder" style="width: 752px;">
<div class="picture" style="width: 722px;">
<img src="https://freedfromtime.files.wordpress.com/2016/08/farmopolis-flowers-dsc_6487.jpg?w=722&h=600" width="722" height="600" alt="">
<div class="captioning"></div>
</div>
</div>
<div class="picture_holder" style="width: 1094px;">
<div class="picture" style="width: 1064px;">
<img src="https://www.openfootage.net/Openfootage/Vorschau/00299_GelbeBluete/00299_GelbeBluete_Preview_v01.jpg" width="1064" height="600" alt="">
<div class="captioning">
<div class="caption"><i>CAPTION</i></div>
</div>
</div>
</div>
<div class="picture_holder" style="width: 1525px;">
<div class="picture" style="width: 1495px;">
<img src="https://static.wixstatic.com/media/09a7b6_b09cf68226774f6d8af396d240573130.jpg/v1/fill/w_1495,h_600,al_c,q_85,usm_0.66_1.00_0.01/09a7b6_b09cf68226774f6d8af396d240573130.webp" width="1495" height="600" alt="">
<div class="captioning"></div>
</div>
</div>
<div class="picture_holder" style="width: 560px;">
<div class="picture" style="width: 530px;">
<img src="http://www.besgroup.org/wp-content/uploads/SunbirdBrTh-Costus-JWee-1.jpg" width="530" height="600" alt="">
<div class="captioning"></div>
</div>
</div>
<!-- mousewheel java script -->
<script type="text/javascript">
function handle(delta) {
if (delta < 0)
ScrollSmoothly(10, 10, 'right');
else if (delta > 0)
ScrollSmoothly(10, 10, 'left');
else
;
}
function wheel(event) {
var delta = 0;
if (!event)
event = window.event;
if (event.wheelDelta) {
delta = event.wheelDelta / 120;
if (window.opera)
delta = -delta;
} else if (event.detail) {
delta = -event.detail / 3;
}
if (delta)
handle(delta);
if (event.preventDefault)
event.preventDefault();
event.returnValue = false;
}
var repeatCount = 0;
function ScrollSmoothly(scrollPos, repeatTimes, direction) {
if (repeatCount < repeatTimes)
if (direction == 'right')
window.scrollBy(20, 0);
else
window.scrollBy(-20, 0);
else {
repeatCount = 0;
clearTimeout(cTimeout);
return;
}
repeatCount++;
cTimeout = setTimeout("ScrollSmoothly('" + scrollPos + "','" + repeatTimes + "','" + direction + "')", 10);
}
/* Initialization code. */
if (window.addEventListener)
window.addEventListener('DOMMouseScroll', wheel, false);
window.onmousewheel = document.onmousewheel = wheel;
</script>
<style type="text/css">
#img-container {
width: 6450px;
}
#img-container #text {
float: left;
width: 675px;
}
#img-container #text p {
width: 600px;
}
#img-container .picture_holder {
float: left;
}
#img-container .picture {
/* padding-top: 100px; */
}
#img-container .captioning .title {
margin-top: 12px;
font-weight: bold;
}
#img-container .captioning .caption {}
</style>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</section>
</div>
<footer class="fttext">
<i class="fa fa-twitter-square fa-2x" aria-hidden="true"></i>
<i class="fa fa-facebook-square fa-2x" aria-hidden="true"></i>
<p>© 2018 Natalie Davis.</p>
</footer>
</body>
</html>
Looking at the code you've posted, in your CSS, your menu styles were targeting an ID, whereas, in your HTML, your menu code had a class instead. Changing the CSS for menu to a class instead of an ID, the styles are then applied, and if the position is changed from absolute to fixed, it then behaves as desired.
.menu {
width: 960px;
margin: 0 auto;
position: fixed;
text-align: center;
background-color: darkred;
}

Swapping an image when a toggle has been clicked on

I have the following code where I added a plus symbol to one of my service titles. I was informed by someone that when that service is clicked on I should have a minus sign take its place to show that it can be minimized. I am unsure of how to swap out the plus sign when the description has been expanded. Does anyone have any ideas of how I could do that?
Here is a snippet. Click on one of the service names to see the description expand.
$('.service_wrapper').click(function() {
var thisDescription = $('.service_description', $(this));
// Hide all other descriptions
$('.service_description').not(thisDescription).hide();
// Toggle (show or hide) this description
thisDescription.slideToggle(500);
});
.service_wrapper {
border: 1px solid black;
margin: 15px;
width: 20%;
}
.service_list {
margin-left: 20%;
}
.service_title {
padding: 15px 12px;
margin: 0;
font-weight: bold;
font-size: 1em;
}
.service_title:hover {
background-color: gray;
color: blue;
cursor: pointer;
}
.service_description {
display: none;
padding: 8px 14px;
width: 100%;
margin-top: 10px;
font-size: .9em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="service_list">
<div class="service_wrapper">
<div class="service_title">
<img src="http://realtorcatch.com/icons/plusSymbol.png" alt="Service" style="width:10px;height:10px;">Floors</div>
<div class="service_description">The best floors!</div>
</div>
<div class="service_wrapper">
<div class="service_title">Roofs</div>
<div class="service_description">Your roof will be perfect!</div>
</div>
<div class="service_wrapper">
<div class="service_title">Siding</div>
<div class="service_description">mmmm siding.</div>
</div>
<div class="service_wrapper">
<div class="service_title">Paint</div>
<div class="service_description">Fabulous paint!</div>
</div>
<div class="service_wrapper">
<div class="service_title">Kitchen Remodels</div>
<div class="service_description">Pretty kitchen.</div>
</div>
</div>
Here is the working example, i change a little de html and Js
$('.service_wrapper').click(function() {
var thisDescription = $('.service_description', $(this));
var t = $(this);
if(t.hasClass('open'))
{
t.removeClass('open');
t.find('.status').html("+");
}else {
t.addClass('open');
t.find('.status').html("-");
}
// Hide all other descriptions
$('.service_description').not(thisDescription).hide();
// Toggle (show or hide) this description
thisDescription.slideToggle(500);
});
the working example
I'd suggest simply toggling a class to achieve this.
You can add the icon as a background image of a pseudo element inserted into the .service_title element. Then you can simply toggle a class in order to change the icon. Update the background image URLs accordingly. See the updated example for the modified jQuery; it's still only 5 lines.
The relevant CSS:
.service_title:before {
content: '';
background: url('http://i.stack.imgur.com/GC7i2.png') 0 0 / 10px 10px no-repeat;
width: 10px;
height: 10px;
display: inline-block;
vertical-align: middle;
}
.closed .service_title:before {
background-image: url('http://i.stack.imgur.com/ma4L4.png');
}
Updated Example:
$('.service_wrapper').click(function() {
var thisDescription = $('.service_description', $(this));
$('.service_description').not(thisDescription).hide().parent().removeClass('closed');
thisDescription.slideToggle(500).parent().toggleClass('closed');
});
.service_wrapper {
border: 1px solid black;
margin: 15px;
width: 20%;
}
.service_list {
margin-left: 20%;
}
.service_title {
padding: 15px 12px;
margin: 0;
font-weight: bold;
font-size: 1em;
}
.service_title:before {
content: '';
background: url('http://i.stack.imgur.com/GC7i2.png') 0 0 / 10px 10px no-repeat;
width: 10px;
height: 10px;
display: inline-block;
vertical-align: middle;
}
.closed .service_title:before {
background-image: url('http://i.stack.imgur.com/ma4L4.png');
}
.service_title:hover {
background-color: gray;
color: blue;
cursor: pointer;
}
.service_description {
display: none;
padding: 8px 14px;
width: 100%;
margin-top: 10px;
font-size: .9em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="service_list">
<div class="service_wrapper">
<div class="service_title">Floors</div>
<div class="service_description">The best floors!</div>
</div>
<div class="service_wrapper">
<div class="service_title">Roofs</div>
<div class="service_description">Your roof will be perfect!</div>
</div>
<div class="service_wrapper">
<div class="service_title">Siding</div>
<div class="service_description">mmmm siding.</div>
</div>
<div class="service_wrapper">
<div class="service_title">Paint</div>
<div class="service_description">Fabulous paint!</div>
</div>
<div class="service_wrapper">
<div class="service_title">Kitchen Remodels</div>
<div class="service_description">Pretty kitchen.</div>
</div>
</div>
You could just change it within your click binding...
Let's say your using images, just add a data-attribute you can query when you need to, like this...
HTML
<div class="service_wrapper">
<img data-state="plus" class="state" src="plus.png" alt="More"/>
<div class="service_title">Paint</div>
<div class="service_description">Fabulous paint!</div>
</div>
JS
$('.service_wrapper').click(function() {
var state = $(this).find('.state');
if(state.data('state') == 'plus')
state.attr({ 'src': 'minus.png', 'alt': 'Less' }).data('state', 'minus');
else
state.attr({ 'src': 'plus.png', 'alt': 'More' }).data('state', 'plus');
});

Categories