I have a portfolio website written using Vue and Laravel that renders out project thumbnails with v-for. This works completely fine on every browser apart from on Safari, there's a weird issue where the images will not show up at all unless the user resizes the browser window. Heres the relevent code:
<div class="project-list">
<img v-show="!loaded" class="loading" src="../assets/contrast_load.gif" alt="loading...">
<div class="project-container" v-for="project in shownProjects.slice().reverse()" v-bind:key="project.id">
<figure class="project" @mouseover="gColor1 = project.color1; gColor2 = project.color2" @click="goToPage(project.id)" :style="`--overlay-color: ${project.color1};`">
<img :src="`${base}/storage/app/${project.thumb_img}`" :alt="project.name" />
<figcaption>
<h3>{{ project.name }} <span v-bind:style="{color: project.color1}">{{ project.description }}</span></h3>
</figcaption>
</figure>
</div>
</div>
</div>
</div>
</template>
<script>
import LogoSVG from '../components/LogoSVG.vue';
import config from '../config';
import axios from 'axios';
export default {
name: 'Portfolio',
data(){
return{
search: '',
projects: [],
shownProjects: [],
loaded: false,
gColor1: '#752323',
gColor2: '#e04747',
base: config.BASE_URL,
}
},
components:{
LogoSVG,
},
watch:{
search(){
const vm = this;
vm.shownProjects = [];
if (vm.search == '') {
vm.shownProjects = vm.projects;
}
else {
for (var i = 0; i < vm.projects.length; i++) {
if(vm.projects[i].tags.toLowerCase().search(vm.search.toLowerCase()) > -1){
vm.shownProjects.push(vm.projects[i]);
}
}
}
},
},
methods:{
getProjects(){
const vm = this;
vm.loaded = false;
axios.get(`${config.APP_URL}/api/projects`)
.then(function (response) {
vm.projects = response.data;
vm.shownProjects = response.data;
window.onload = function() {
vm.loaded = true;
};
});
},
goToPage(r){
this.$router.push('project/' + r);
},
}
}
</script>
<style scoped>
.loading{
position: absolute;
width: 50px;
height: 50px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.project-list{
width: 90%;
height: 70%;
position: absolute;
display: flex;
display: -webkit-flex;
flex-wrap: wrap;
justify-content: flex-start;
left: 50%;
top: 65%;
transform: translate(-50%, -50%);
align-content: flex-start;
overflow-y: scroll;
overflow-x: hidden;
}
.project-container{
width: 33%;
height: 30vh;
}
.project {
background-color: #2A2A2A;
color: #FFF;
font-family: 'Roboto', sans-serif;
font-size: 18px;
margin: 8px;
max-width: 100%;
min-width: 230px;
overflow: hidden;
position: relative;
text-align: center;
width: 100%;
height: 100%;
cursor: pointer;
}
.project * {
-webkit-box-sizing: border-box;
box-sizing: border-box;
-webkit-transition: all 0.45s ease;
transition: all 0.45s ease;
cursor: pointer;
}
.project:after {
background-color: var(--overlay-color);
height: 150%;
bottom: -145%;
content: '';
left: 0;
right: 0;
position: absolute;
-webkit-transition: all 0.2s linear;
transition: all 0.4s linear;
cursor: pointer;
}
.project img {
vertical-align: top;
backface-visibility: hidden;
max-height: 100%;
object-fit: cover;
}
.project figcaption {
position: absolute;
top: 0;
bottom: 0;
left: 10%;
right: 10%;
align-items: center;
z-index: 1;
display: flex;
width: 80%;
flex-direction: column;
justify-content: center;
line-height: 1.1em;
opacity: 0;
-webkit-transition-delay: 0s;
transition-delay: 0s;
}
.project h3 {
font-size: 1em;
font-weight: 400;
letter-spacing: 1px;
margin: 0;
text-transform: uppercase;
}
.project h3 span {
display: block;
font-weight: 700;
}
.project a {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 1;
}
.project:hover > img,
.project.hover > img {
opacity: 0.1;
}
.project:hover:after,
.project.hover:after {
bottom: 95%;
}
.project:hover figcaption,
.project.hover figcaption {
opacity: 1;
-webkit-transition-delay: 0.3s;
transition-delay: 0.3s;
}
.project-fade-leave-active,
.project-fade-enter-active {
transition: 0.4s all;
}
.project-fade-enter,
.project-fade-leave-to {
opacity: 0;
}
@-webkit-keyframes fadeDown {
0% {
top: 4vh;
opacity: 0;
}
100%{
top: 5vh;
opacity: 1;
}
}
@-webkit-keyframes fade {
0% {
opacity: 0;
}
100%{
opacity: 1;
}
}
</style>
and you can visit the page here: https://www.redsquirrelstudio.co.uk/#/portfolio
Any help would be greatly appreciated this has been a real headache.
Found out the issue. Apparently safari isn't the best with reacting to changes in data in Vue. I added an element in that changes when the rest of the data loads which triggers everything else to update.
Very strange.
Just in case anyone finds this question in the future (like me) I would like to point out a few things that made Safari render the correct data from the state:
Use a v-bind
directive in any element that fails to update. In my case, my div ended up like <div :key="targetObject.guid">
.
Use dummy CSS properties for elements that also need to be updated. The ones I used were the following:
.problematic-element {
display: inline-block;
min-width: 0%;
transform: translateZ(0);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With