body {
font-family: ‘Segoe UI’, Tahoma, Geneva, Verdana, sans-serif;
max-width: 100%;
margin: 0 auto;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
h1, h2, h3 {
color: #2c3e50;
}
.container {
background: rgba(255, 255, 255, 0.95);
padding: 30px;
border-radius: 15px;
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
backdrop-filter: blur(10px);
max-width: 100%;
margin: 0 auto;
}
.subscription-form {
background: linear-gradient(135deg, #e8f4f8 0%, #d4f1f4 100%);
padding: 25px;
border-radius: 12px;
margin-bottom: 30px;
border: 1px solid rgba(52, 152, 219, 0.2);
}
.exercise-container {
display: none;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
color: #2c3e50;
}
input, select, textarea {
width: 100%;
padding: 12px;
border: 2px solid #e9ecef;
border-radius: 8px;
font-size: 16px;
transition: border-color 0.3s ease;
}
input:focus, select:focus, textarea:focus {
outline: none;
border-color: #3498db;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
}
button {
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
color: white;
border: none;
padding: 15px 25px;
border-radius: 8px;
cursor: pointer;
font-size: 16px;
font-weight: bold;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(52, 152, 219, 0.3);
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(52, 152, 219, 0.4);
}
.question {
margin-bottom: 25px;
padding: 25px;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-radius: 12px;
border-left: 5px solid #3498db;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}
.question-number {
font-weight: bold;
color: #2c3e50;
margin-bottom: 12px;
font-size: 18px;
}
.question-text {
font-size: 16px;
margin-bottom: 15px;
line-height: 1.6;
color: #2c3e50;
}
.question-type {
background: #3498db;
color: white;
padding: 4px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: bold;
display: inline-block;
margin-bottom: 10px;
}
.options {
display: grid;
gap: 12px;
}
.option {
display: flex;
align-items: center;
padding: 12px;
background: white;
border: 2px solid #e9ecef;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
}
.option:hover {
border-color: #3498db;
background: linear-gradient(135deg, #f0f8ff 0%, #e6f3ff 100%);
transform: translateX(5px);
}
.option input[type=”radio”], .option input[type=”checkbox”] {
margin-right: 12px;
width: auto;
transform: scale(1.2);
}
.option.correct {
background: linear-gradient(135deg, #d4edda 0%, #c3e6cb 100%);
border-color: #28a745;
}
.option.incorrect {
background: linear-gradient(135deg, #f8d7da 0%, #f1b0b7 100%);
border-color: #dc3545;
}
.option.correct-answer {
background: linear-gradient(135deg, #d1ecf1 0%, #bee5eb 100%);
border-color: #17a2b8;
}
.fill-blank {
background: white;
border: 2px solid #3498db;
border-radius: 6px;
padding: 8px 12px;
margin: 0 5px;
min-width: 120px;
text-align: center;
font-weight: bold;
}
.result {
margin-top: 30px;
padding: 25px;
background: linear-gradient(135deg, #eafaf1 0%, #d4f1de 100%);
border-radius: 12px;
display: none;
border: 1px solid rgba(40, 167, 69, 0.2);
}
.certificate {
text-align: center;
margin-top: 30px;
padding: 25px;
border: 3px solid #2c3e50;
border-radius: 12px;
display: none;
background: white;
}
.error {
color: #dc3545;
font-size: 14px;
margin-top: 5px;
}
.progress-bar {
width: 100%;
height: 25px;
background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);
border-radius: 15px;
margin-bottom: 25px;
overflow: hidden;
box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
}
.progress-fill {
height: 100%;
background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
border-radius: 15px;
transition: width 0.5s ease;
width: 0%;
box-shadow: 0 2px 4px rgba(40, 167, 69, 0.3);
}
#certificatePreview {
position: relative;
width: 100%;
height: 500px;
background: linear-gradient(135deg, #fff 0%, #f8f9fa 100%);
border: 12px solid transparent;
border-image: linear-gradient(45deg, #3498db, #2980b9, #1abc9c, #16a085, #27ae60) 1;
box-sizing: border-box;
overflow: hidden;
margin-bottom: 25px;
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
}
.certificate-content {
position: relative;
z-index: 1;
padding: 25px;
width: 100%;
height: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.certificate-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.certificate-title {
flex-grow: 1;
text-align: center;
}
.certificate-logo {
width: 140px;
height: 70px;
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
font-size: 18px;
}
.certificate-footer {
display: flex;
justify-content: space-between;
align-items: flex-end;
}
.certificate-qr {
width: 120px;
height: 120px;
display: flex;
justify-content: center;
align-items: center;
background: #f9f9f9;
border: 2px solid #dee2e6;
border-radius: 8px;
}
.certificate-signature {
flex-grow: 1;
text-align: center;
}
.loading {
display: none;
margin-top: 15px;
font-style: italic;
color: #6c757d;
text-align: center;
}
.instruction-box {
background: linear-gradient(135deg, #fff3cd 0%, #ffeaa7 100%);
border: 2px solid #ffeaa7;
border-radius: 12px;
padding: 20px;
margin-bottom: 25px;
}
.theme-section {
margin-bottom: 35px;
padding: 25px;
background: linear-gradient(135deg, #f1f3f4 0%, #e8eaed 100%);
border-radius: 12px;
border-left: 6px solid #e74c3c;
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
}
.theme-title {
color: #e74c3c;
font-size: 20px;
font-weight: bold;
margin-bottom: 20px;
text-transform: uppercase;
letter-spacing: 1px;
}
.multiple-choice-container {
display: grid;
gap: 10px;
}
.score-display {
font-size: 24px;
font-weight: bold;
color: #27ae60;
text-align: center;
margin: 20px 0;
padding: 15px;
background: linear-gradient(135deg, #d4f1de 0%, #c3e6cb 100%);
border-radius: 10px;
}
🎯 Quiz de Français – Niveau B1
Testez vos connaissances sur la grammaire française de niveau intermédiaire ! Ce quiz couvre les points essentiels du niveau B1.
🏆 Quiz Français B1 – Grammaire et Lexique
📋 Instructions: Ce quiz évalue vos compétences en français niveau B1 :
- 🔹 Questions à choix multiples
- 🔹 Complétion de phrases
- 🔹 Questions à réponses multiples
- 🔹 Conjugaisons et accords
Thèmes B1: Mise en relief • Opposition • Futur simple • Subjonctif présent • Pronoms possessifs • Projets • Passé composé/Imparfait • Indicateurs temporels • Accord du participe passé • Généalogie
📊 Résultats de votre Quiz B1
🎓 Certificat de Réussite – Niveau B1
CERTIFICAT DE MAÎTRISE
Français B1 – Niveau Intermédiaire
Ce certificat atteste que
a démontré sa maîtrise du français niveau B1
dans les domaines suivants:
Mise en relief • Opposition • Futur simple • Subjonctif présent
Pronoms possessifs • Expression des projets • Passé composé/Imparfait
Indicateurs temporels • Accord du participe passé • Généalogie
Date:
document.addEventListener(‘DOMContentLoaded’, function() {
// Configuration du quiz B1
const totalQuestions = 35;
const passingScore = 70;
// Références aux éléments DOM
const subscriptionForm = document.getElementById(‘subscriptionForm’);
const exerciseContainer = document.getElementById(‘exerciseContainer’);
const startButton = document.getElementById(‘startButton’);
const verifyButton = document.getElementById(‘verifyButton’);
const resultContainer = document.getElementById(‘resultContainer’);
const scoreDisplay = document.getElementById(‘scoreDisplay’);
const resultText = document.getElementById(‘resultText’);
const mistakesContainer = document.getElementById(‘mistakesContainer’);
const showCertificateButton = document.getElementById(‘showCertificateButton’);
const certificateContainer = document.getElementById(‘certificateContainer’);
const downloadCertificateButton = document.getElementById(‘downloadCertificateButton’);
const pdfLoading = document.getElementById(‘pdfLoading’);
const progressFill = document.getElementById(‘progressFill’);
// Données utilisateur
let userData = {
prenom: ”,
nom: ”,
email: ”,
score: 0
};
// Démarrer le quiz
startButton.addEventListener(‘click’, function() {
if (validateForm()) {
subscriptionForm.style.display = ‘none’;
exerciseContainer.style.display = ‘block’;
exerciseContainer.scrollIntoView({ behavior: ‘smooth’ });
}
});
// Validation du formulaire
function validateForm() {
const prenom = document.getElementById(‘prenom’).value.trim();
const nom = document.getElementById(‘nom’).value.trim();
const email = document.getElementById(‘email’).value.trim();
const subscribe = document.getElementById(‘subscribe’).checked;
clearErrors();
let isValid = true;
if (!prenom) {
showError(‘prenomError’, ‘Veuillez entrer votre prénom’);
isValid = false;
}
if (!nom) {
showError(‘nomError’, ‘Veuillez entrer votre nom’);
isValid = false;
}
if (!email) {
showError(‘emailError’, ‘Veuillez entrer votre email’);
isValid = false;
} else if (!/^[^s@]+@[^s@]+.[^s@]+$/.test(email)) {
showError(‘emailError’, ‘Veuillez entrer un email valide’);
isValid = false;
}
if (!subscribe) {
showError(‘subscribeError’, ‘Veuillez accepter de vous abonner’);
isValid = false;
}
if (isValid) {
userData.prenom = prenom;
userData.nom = nom;
userData.email = email;
}
return isValid;
}
function clearErrors() {
const errorElements = [‘prenomError’, ‘nomError’, ‘emailError’, ‘subscribeError’];
errorElements.forEach(id => {
document.getElementById(id).textContent = ”;
});
}
function showError(elementId, message) {
document.getElementById(elementId).textContent = message;
}
// Mettre à jour la barre de progression
function updateProgress() {
const answeredQuestions = getAnsweredQuestionsCount();
const progress = (answeredQuestions / totalQuestions) * 100;
progressFill.style.width = progress + ‘%’;
}
function getAnsweredQuestionsCount() {
let count = 0;
for (let i = 1; i 0) {
let allFilled = true;
fillBlanks.forEach(blank => {
if (!blank.value.trim()) {
allFilled = false;
}
});
if (allFilled) count++;
}
}
}
return count;
}
// Écouter les changements
document.addEventListener(‘change’, updateProgress);
document.addEventListener(‘input’, updateProgress);
// Vérifier les réponses
verifyButton.addEventListener(‘click’, function() {
const results = checkAnswers();
displayResults(results);
});
function checkAnswers() {
let correctAnswers = 0;
const mistakes = [];
const questions = document.querySelectorAll(‘.question[data-answer]’);
questions.forEach((question, index) => {
const questionNum = index + 1;
const type = question.dataset.type;
const correctAnswer = question.dataset.answer;
let isCorrect = false;
let userAnswer = ”;
let correctText = ”;
if (type === ‘single’) {
const selectedRadio = question.querySelector(`input[type=”radio”]:checked`);
if (selectedRadio) {
userAnswer = selectedRadio.value;
isCorrect = userAnswer === correctAnswer;
// Marquer visuellement les réponses
const options = question.querySelectorAll(‘.option’);
options.forEach(option => {
option.classList.remove(‘correct’, ‘incorrect’, ‘correct-answer’);
});
if (isCorrect) {
selectedRadio.closest(‘.option’).classList.add(‘correct’);
} else {
selectedRadio.closest(‘.option’).classList.add(‘incorrect’);
const correctOption = question.querySelector(`input[value=”${correctAnswer}”]`);
if (correctOption) {
correctOption.closest(‘.option’).classList.add(‘correct-answer’);
}
}
}
} else if (type === ‘multiple’) {
const selectedCheckboxes = question.querySelectorAll(`input[type=”checkbox”]:checked`);
const selectedValues = Array.from(selectedCheckboxes).map(cb => cb.value).sort();
const correctValues = correctAnswer.split(‘,’).sort();
isCorrect = JSON.stringify(selectedValues) === JSON.stringify(correctValues);
userAnswer = selectedValues.join(‘, ‘);
correctText = correctValues.join(‘, ‘);
// Marquer visuellement
const allCheckboxes = question.querySelectorAll(‘input[type=”checkbox”]’);
allCheckboxes.forEach(cb => {
const option = cb.closest(‘.option’);
option.classList.remove(‘correct’, ‘incorrect’, ‘correct-answer’);
if (cb.checked) {
if (correctValues.includes(cb.value)) {
option.classList.add(‘correct’);
} else {
option.classList.add(‘incorrect’);
}
} else if (correctValues.includes(cb.value)) {
option.classList.add(‘correct-answer’);
}
});
} else if (type === ‘fill’) {
const fillBlanks = question.querySelectorAll(‘.fill-blank’);
const correctValues = correctAnswer.split(‘,’);
let allCorrect = true;
fillBlanks.forEach((blank, i) => {
const userValue = blank.value.trim().toLowerCase();
const expectedValue = correctValues[i].trim().toLowerCase();
if (userValue !== expectedValue) {
allCorrect = false;
blank.style.borderColor = ‘#dc3545’;
blank.style.backgroundColor = ‘#f8d7da’;
} else {
blank.style.borderColor = ‘#28a745’;
blank.style.backgroundColor = ‘#d4edda’;
}
});
isCorrect = allCorrect;
userAnswer = Array.from(fillBlanks).map(blank => blank.value.trim()).join(‘, ‘);
correctText = correctAnswer.replace(/,/g, ‘, ‘);
}
if (isCorrect) {
correctAnswers++;
} else {
const questionText = question.querySelector(‘.question-text’).textContent.trim();
mistakes.push({
number: questionNum,
question: questionText,
userAnswer: userAnswer || ‘Pas de réponse’,
correctAnswer: correctText || correctAnswer
});
}
});
const percentage = Math.round((correctAnswers / totalQuestions) * 100);
userData.score = percentage;
return {
correct: correctAnswers,
total: totalQuestions,
percentage: percentage,
mistakes: mistakes
};
}
function displayResults(results) {
scoreDisplay.textContent = `${results.percentage}%`;
let message = ”;
let showCertificate = false;
if (results.percentage >= 90) {
message = ‘🎉 Excellent ! Vous maîtrisez parfaitement le français B1 !’;
showCertificate = true;
scoreDisplay.style.color = ‘#27ae60’;
} else if (results.percentage >= passingScore) {
message = ‘👍 Très bien ! Vous avez un bon niveau B1 en français.’;
showCertificate = true;
scoreDisplay.style.color = ‘#27ae60’;
} else if (results.percentage >= 50) {
message = ‘📚 Pas mal ! Continuez à pratiquer pour améliorer votre niveau B1.’;
scoreDisplay.style.color = ‘#f39c12’;
} else {
message = ‘💪 Il faut encore travailler. Révisez les points de grammaire B1 et recommencez !’;
scoreDisplay.style.color = ‘#e74c3c’;
}
resultText.textContent = message;
// Afficher les erreurs
if (results.mistakes.length > 0) {
let mistakesHtml = ‘
📝 Questions à revoir :
‘;
results.mistakes.forEach(mistake => {
mistakesHtml += `
Votre réponse: ${mistake.userAnswer}
Réponse correcte: ${mistake.correctAnswer}
`;
});
mistakesContainer.innerHTML = mistakesHtml;
} else {
mistakesContainer.innerHTML = ‘
🎯 Parfait ! Toutes vos réponses sont correctes !
‘;
}
if (showCertificate) {
showCertificateButton.style.display = ‘inline-block’;
}
resultContainer.style.display = ‘block’;
resultContainer.scrollIntoView({ behavior: ‘smooth’ });
// Désactiver le bouton de vérification
verifyButton.disabled = true;
verifyButton.textContent = ‘✅ Réponses vérifiées’;
verifyButton.style.opacity = ‘0.6’;
}
// Afficher le certificat
showCertificateButton.addEventListener(‘click’, function() {
document.getElementById(‘certificateName’).textContent = `${userData.prenom} ${userData.nom}`;
document.getElementById(‘certificateScore’).textContent = `${userData.score}%`;
document.getElementById(‘certificateDate’).textContent = new Date().toLocaleDateString(‘fr-FR’);
certificateContainer.style.display = ‘block’;
certificateContainer.scrollIntoView({ behavior: ‘smooth’ });
});
// Télécharger le certificat PDF
downloadCertificateButton.addEventListener(‘click’, function() {
generatePDF();
});
function generatePDF() {
pdfLoading.style.display = ‘block’;
downloadCertificateButton.disabled = true;
const element = document.getElementById(‘certificatePreview’);
html2canvas(element, {
scale: 2,
useCORS: true,
allowTaint: true,
backgroundColor: ‘#ffffff’
}).then(canvas => {
const imgData = canvas.toDataURL(‘image/png’);
const { jsPDF } = window.jspdf;
// Format A4 paysage
const pdf = new jsPDF(‘landscape’, ‘mm’, ‘a4’);
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
// Calculer les dimensions pour centrer l’image
const imgWidth = pdfWidth – 20; // Marges de 10mm de chaque côté
const imgHeight = (canvas.height * imgWidth) / canvas.width;
const x = 10; // Marge gauche
const y = (pdfHeight – imgHeight) / 2; // Centrer verticalement
pdf.addImage(imgData, ‘PNG’, x, y, imgWidth, imgHeight);
// Métadonnées du PDF
pdf.setProperties({
title: `Certificat Français B1 – ${userData.prenom} ${userData.nom}`,
subject: ‘Certificat de maîtrise du français niveau B1’,
author: ‘Français Langue Française’,
creator: ‘Quiz B1 Generator’
});
const filename = `Certificat_Francais_B1_${userData.prenom}_${userData.nom}_${userData.score}pct.pdf`;
pdf.save(filename);
pdfLoading.style.display = ‘none’;
downloadCertificateButton.disabled = false;
}).catch(error => {
console.error(‘Erreur lors de la génération du PDF:’, error);
alert(‘Erreur lors de la génération du PDF. Veuillez réessayer.’);
pdfLoading.style.display = ‘none’;
downloadCertificateButton.disabled = false;
});
}
// Fonction pour normaliser les réponses (ignorer les accents, majuscules, espaces)
function normalizeAnswer(answer) {
return answer.toLowerCase()
.trim()
.normalize(‘NFD’)
.replace(/[u0300-u036f]/g, ”) // Supprimer les accents
.replace(/s+/g, ‘ ‘); // Normaliser les espaces
}
// Améliorer la vérification des réponses à remplir
function checkFillAnswer(userAnswer, correctAnswer) {
const normalizedUser = normalizeAnswer(userAnswer);
const normalizedCorrect = normalizeAnswer(correctAnswer);
// Vérification exacte
if (normalizedUser === normalizedCorrect) {
return true;
}
// Vérifications alternatives pour certaines réponses
const alternatives = {
‘cest’: [‘c’est’, ‘cest’],
‘dabord’: [‘d’abord’, ‘dabord’],
‘arrriere-grand-pere’: [‘arrière-grand-père’, ‘arriere-grand-pere’, ‘arrière grand père’],
‘belle-fille’: [‘belle-fille’, ‘belle fille’, ‘bellefille’]
};
for (const [key, values] of Object.entries(alternatives)) {
if (values.some(alt => normalizeAnswer(alt) === normalizedCorrect)) {
return values.some(alt => normalizeAnswer(alt) === normalizedUser);
}
}
return false;
}
// Initialiser la barre de progression
updateProgress();
// Ajouter des animations aux éléments
function addAnimations() {
const questions = document.querySelectorAll(‘.question’);
questions.forEach((question, index) => {
question.style.opacity = ‘0’;
question.style.transform = ‘translateY(20px)’;
question.style.transition = ‘all 0.5s ease’;
setTimeout(() => {
question.style.opacity = ‘1’;
question.style.transform = ‘translateY(0)’;
}, index * 100);
});
}
// Ajouter un effet de survol aux options
document.querySelectorAll(‘.option’).forEach(option => {
option.addEventListener(‘mouseenter’, function() {
this.style.transform = ‘translateX(5px)’;
});
option.addEventListener(‘mouseleave’, function() {
if (!this.classList.contains(‘correct’) &&
!this.classList.contains(‘incorrect’) &&
!this.classList.contains(‘correct-answer’)) {
this.style.transform = ‘translateX(0)’;
}
});
});
// Démarrer les animations quand l’exercice est affiché
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.target.id === ‘exerciseContainer’ &&
mutation.target.style.display === ‘block’) {
setTimeout(addAnimations, 500);
}
});
});
observer.observe(exerciseContainer, {
attributes: true,
attributeFilter: [‘style’]
});
// Validation en temps réel pour les champs de saisie
document.querySelectorAll(‘.fill-blank’).forEach(input => {
input.addEventListener(‘blur’, function() {
const question = this.closest(‘.question’);
if (question && question.dataset.type === ‘fill’) {
// Réinitialiser le style
this.style.borderColor = ‘#3498db’;
this.style.backgroundColor = ‘white’;
}
});
});
});