'Vue.js rendering issues with safari
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.
Solution 1:[1]
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.
Solution 2:[2]
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);
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | RedSquirrel Studio |
Solution 2 | lagunatenofelix |